SQLiteOpenHelper.setWriteAheadLoggingEnabled导致错误日志行

时间:2015-02-07 17:21:28

标签: android android-sqlite

当我打电话

setWriteAheadLoggingEnabled(true);

在我的SQLiteOpenHelper子类的构造函数中,第一次使用数据库时,在创建它之后,我可以看到以下错误日志项:

02-07 18:16:05.131  10426-10426/com.test E/SQLiteLog﹕ (1) no such table: test

当应用程序被杀死并随后开始时,我得到:

E/SQLiteLog﹕ (283) recovered 10 frames from WAL file /data/data/com.test/databases/test-wal

但是,应用程序运行正常,实际上没有异常抛出。

当我不启用WAL时,日志项不存在。

日志错误是否需要担心?

修改:我DbHelper的代码:

public class DbHelper extends SQLiteOpenHelper {

private static final int DB_VERSION = 1;

public DbHelper(Context context) {
    super(context, Db.NAME, null, DB_VERSION);

    // setWriteAheadLoggingEnabled(true);
}

@Override
public void onConfigure(SQLiteDatabase db) {
    super.onConfigure(db);

    db.setForeignKeyConstraintsEnabled(true);
    db.enableWriteAheadLogging();
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(Db.TestGroup._CREATE_TABLE);
    db.execSQL(Db.Test._CREATE_TABLE);
    db.execSQL(Db.Task._CREATE_TABLE);
    db.execSQL(Db.TaskFullTextSearch._CREATE_TABLE);

    db.execSQL(Db.TaskFullTextSearch.Triggers.AFTER_INSERT);
    db.execSQL(Db.TaskFullTextSearch.Triggers.BEFORE_UPDATE);
    db.execSQL(Db.TaskFullTextSearch.Triggers.AFTER_UPDATE);
    db.execSQL(Db.TaskFullTextSearch.Triggers.BEFORE_DELETE);
}

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

public int getTestCount() {
    Cursor cursor = getReadableDatabase().rawQuery(SELECT_TEST_COUNT, null);
    cursor.moveToNext();
    int count = cursor.getInt(0);
    cursor.close();

    return count;
}
}

数据库类是一个合同' class,定义表类和列以及一堆SQL语句。

数据库助手是在自定义Application子类中创建的单例:

public class TestApplication extends Application {

private static DbHelper DB_HELPER;

@Override
public void onCreate() {
    super.onCreate();

    DB_HELPER = new DbHelper(getApplicationContext());
}

public static DbHelper getDbHelper() {
    return DB_HELPER;
}
}

编辑2 :我刚检查了当没有test表时会发生什么 - 应用程序崩溃:

E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.test, PID: 30663
android.database.sqlite.SQLiteException: no such table: test (code 1): , while compiling: select count(*) from test

1 个答案:

答案 0 :(得分:3)

经过一些实验,似乎由于某种原因,SQLite将缓存的表列表作为与打开的连接相关联的元数据的一部分。创建新表仅更新用于执行此操作的连接上的缓存。如果连接用于对未包含在其缓存的元数据中的表执行某些操作,则它会抱怨该表不存在,即使操作本身已成功执行(并且缓存随后更新)。

如果未启用预写日志记录,SQLiteDatabase使用的连接池当前只允许一个连接用于读取和写入操作,可能是为了避免在写入器执行时执行读取操作而导致的错误数据库上的独占锁。如果启用了预写日志记录,则除了主写入连接之外,它还允许至少一个单独的读取连接(读取连接的确切限制由系统属性定义)。

SQLiteOpenHelper打开一个读连接,用于在打开用于数据库初始化和升级/降级的写连接之前获取版本信息。如果未启用预写日志记录,则它们都是相同的连接。但是,如果在初始化之前启用了预写日志记录,则读取连接的缓存不会反映初始化期间执行的任何结构更改(并且SQLite在第一个查询时在日志中抱怨执行)。这可以通过从onOpen()方法启用预写日志记录来修复,该方法在初始化完成后调用。

关于帧恢复的日志,这是由SQLite检查点并在所有连接关闭时删除WAL文件引起的。如果终止持有连接的进程而没有显式关闭它们,则在随后打开新连接时执行此清理,并且SQLite会抱怨它。如果您将应用程序移至后台时关闭SQLiteDatabase,则应解决此问题。另一方面,如果您在整个应用程序中与数据库进行交互,那么这可能会有问题并且难以实现,我也不建议这样做。