1

最终编辑,问题“已解决”

所以我最终按照接受的答案做了什么,我删除了将数据库版本作为参数的构造函数,但这仍然导致异常。因此,正如还建议的那样,我添加try{} catch{}了一个块来捕获问题,让我告诉你,它仍然显示抛出异常,只是这次它不会使应用程序崩溃。幸运的是,尽管创建数据库似乎有问题,但它允许我将数据库内容加载到应用程序中,所以我现在对那个日志消息很好:)

这是 onCreate:

@Override
public void onCreate(SQLiteDatabase db) {
    Constants.logMessage("Creating database from scratch?");
    //Create both of the tables as part of the databases
    try {
        db.execSQL(CREATE_TABLE_COUNTRIES);
        db.execSQL(CREATE_TABLE_REGIONS);
        db.execSQL(CREATE_TABLE_CITIES);
    }
    catch (Exception e) {
        //This happens on every launch that isn't the first one. 
        Log.w("SpotTheStation", "Error while creating db: " + e.toString());
    }       
}

我在我的 android 应用程序上使用 SQLite,似乎遇到了一个非常奇怪的问题。似乎每次我调用getWriteableDatabase()系统都会尝试重新创建整个数据库,即它调用onCreate(),这会导致 SQLiteException。

这是完整的错误消息:

03-21 14:36:44.082: V/SpotTheStation(20034): android.database.sqlite.SQLiteException:, 
while compiling: create table countries(_id integer primary key autoincrement,
country text);

每次我尝试访问 DBdata 时都会发生这种情况,我有一个单独的静态类来处理整个应用程序生命周期中的 DB 访问,我通过以下方式将上下文传递给它:

public static Cursor getCountries (final Context context) {

    if (mDatabase == null || !mDatabase.isOpen()) {
        Constants.logMessage("DB was null, opening");
        open(context);
    }

    return mDatabase.query(CountryDbHelper.TABLE_COUNTRIES, CountryDbHelper.PROJECTION_COUNTRIES, null, null, null, null, CountryDbHelper.DEFAULT_SORT_ORDER);          
}

每次我调用这个方法时,日志都会指出实际上是在打开数据库,这很好。这是我打开数据库的方法:

private static void open (Context context) {
    if (mDatabase != null && mDatabase.isOpen()) {
        return;
    }
    try {
        mHelper = new CountryDbHelper(context);
        mDatabase = mHelper.getWritableDatabase();
    } catch (Exception e) {
        Constants.logMessage(e.toString());
    }
}

这就是导致异常的语句,因为 getWriteableDatabase 应该有一个缓存的数据库,或者应该调用onOpen()而不是onCreate().

这是似乎在每个 db 访问调用上执行的 create 语句:

private static final String DATABASE_CREATE = "create table " + TABLE_COUNTRIES 
        + "(_id integer primary key autoincrement, " 
        + "country text);"
        ;

onCreate()是相当简单的:

@Override
public void onCreate(SQLiteDatabase db) {
    Constants.logMessage("Creating database from scratch?");
    db.execSQL(DATABASE_CREATE);
}

我添加了日志消息来跟踪问题,这是进展情况:

03-21 14:36:44.004: V/SpotTheStation(20034): DB was null, opening
03-21 14:36:44.035: V/SpotTheStation(20034): Creating database from scratch?
03-21 14:36:44.082: V/SpotTheStation(20034): android.database.sqlite.SQLiteException: table countries already exists (code 1): , while compiling: create table countries(_id integer primary key autoincrement, country text);

现在,这让我感到困扰,我在其他一些应用程序上具有相同的 DB 结构(相同的逻辑,一个非静态 OpenHelper 和一个用于访问 dB 内容的静态管理器),并且一切正常,不知道是什么导致这里的问题。

我会很感激一些帮助。

快速编辑

为了更清楚一点,第一次启动(应用程序第一次运行)时getCountries 确实有效,后续运行将导致异常。卸载重新安装过程使其再次工作,然后在第二次运行时死亡。

编辑二号

根据要求,这是 OpenHelper 的完整代码:

public class CountryDbHelper extends SQLiteOpenHelper {

/**
 * This path is hardcoded, during the first time application opens
 * we copy a database file from the assets folder into this folder. 
 */
public final static String DB_PATH = "/data/data/com.nasa.apps.spotthestation/databases/";
private static final int DB_VERSION = 2;
public static String DB_NAME = "countries";
public static final String TABLE_COUNTRIES = "countries";
public static final String TABLE_REGIONS = "regions";
public static final String DEFAULT_SORT_ORDER = "_id";
public static final String [] PROJECTION_COUNTRIES = {
    "_id",
    "country"
};

public static final String [] PROJECTION_REGIONS = {
    "_id",
    "country",
    "region"
};

/**
 * Table with only countries
 */
private static final String CREATE_TABLE_COUNTRIES = "create table " + TABLE_COUNTRIES 
        + "(_id integer primary key autoincrement, " 
        + "country text);"
        ;

/**
 * Table that contains regions per country
 */
private static final String CREATE_TABLE_REGIONS = "create table " + TABLE_REGIONS 
        + "(_id integer primary key autoincrement, " 
        + "country text, "
        + "region text);"
        ;

/**
 * Not used for now
 */
private static final String CREATE_TABLE_CITIES = "create table " + TABLE_COUNTRIES 
        + "(_id integer primary key autoincrement, " 
        + "country text, "
        + "region text, "
        + "city text);"
        ;

public CountryDbHelper(Context context, CursorFactory factory,
        int version) {
    super(context, DB_NAME, factory, version);
}

public CountryDbHelper (Context context) {
    super(context, DB_NAME, null, DB_VERSION );
}

@Override
public void onCreate(SQLiteDatabase db) {
    Constants.logMessage("Creating database from scratch?");
    //Create both of the tables as part of the databases
    db.execSQL(CREATE_TABLE_COUNTRIES);
    db.execSQL(CREATE_TABLE_REGIONS);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    Constants.logMessage("Upgrading db from " + oldVersion + " to new version: " + newVersion);
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_COUNTRIES);
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_REGIONS);
    onCreate(db);
}
}

另外,我注意到的一件事是 /data/data/packageName/databases/ 上的数据库文件没有“sqlite_sequence”文件,该文件通常存储数据库中每个表的行数。我认为问题可能是该文件丢失,因为这两个表使用“主键自动增量”,并且我相信它依赖于知道插入时要使用的下一个 _id 是什么。任何人都可以证实这一点?

再次编辑以防万一,我继续将数据类型从“_id”字段更改autoincrement为简单numeric,因为我不打算向数据库添加更多数据,这是一个只读意图,但它仍然强制关闭第二次发射。

谢谢!

4

2 回答 2

2

你在类构造函数中添加这个super(context, DATABASE_NAME, null, DATABASE_VERSION);

private static class DatabaseHelper extends SQLiteOpenHelper{
        DatabaseHelper(Context context){
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
            @Override
            public void onCreate(SQLiteDatabase db){
                try{
                    db.execSQL(TABLE_CREATE);
                } catch (SQLException e){
                    e.printStackTrace();
                }
            }

            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){

                db.execSQL("DROP TABLE IF EXISTS "+DATABASE_TABLE);
                onCreate(db);
            }       
        }
于 2013-03-21T23:30:13.490 回答
0

我遇到了这个问题,在 DROP TABLE 行的末尾添加一个 <<;>> 解决了我的问题。

db.execSQL("DROP TABLE IF EXISTS " + TABLE_COUNTRIES + ";");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_REGIONS + ";");

不要忘记在需要时更改版本。

于 2013-08-02T02:04:43.977 回答