SQLiteOpenHelper.setWriteAheadLoggingEnabled导致错误日志行
当我打电话SQLiteOpenHelper.setWriteAheadLoggingEnabled导致错误日志行
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;
}
}
DB类是“契约”类定义的表类和列一串SQL语句。
数据库助手是一个自定义的应用程序子类中创建一个单:
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
经过一番实验,看起来由于某种原因,SQLite将表的缓存列表保存为与打开的连接关联的元数据的一部分。创建新表只会更新用于执行此操作的连接上的缓存。如果使用连接对未包含在缓存元数据中的表执行某些操作,那么即使操作本身成功执行(并且随后更新缓存),它也会抱怨该表不存在。
通过SQLiteDatabase
使用的连接池目前只允许一个连接读取和如果未启用预写日志,大概是为了避免因执行读操作错误写操作,而一个作家上具有独占锁数据库。如果启用预写式日志记录,则除了主写连接之外,它还允许至少一个单独的读连接(读连接的确切限制由系统属性定义)。
SQLiteOpenHelper
打开读取连接以获取版本信息之前打开用于数据库初始化和升级/降级的写入连接。如果预写式日志记录未启用,则它们都是相同的连接。但是,如果预写日志记录在初始化之前启用,则读连接的高速缓存不会反映在初始化过程中执行的任何结构更改(并且SQLite会在执行第一个查询时在日志中抱怨)。这可以通过从初始化完成后调用的onOpen()
方法启用预写日志记录来解决。
至于日志约架回收,这是由事实SQLite的检查点,并删除WAL文件时,所有的连接被关闭造成的。如果持有连接的进程在没有明确关闭的情况下终止,那么当新连接随后打开时执行此清理,并且SQLite会对此进行投诉。如果您在应用程序移至后台时关闭SQLiteDatabase
,则应解决此问题。另一方面,如果您在整个应用程序中与数据库进行交互,那么可能会出现问题并且难以实施,我不建议这样做。
谢谢。所以我只会考虑第一个错误信息(关于缺少的表)是一个虚假的信息,这是一个令人讨厌的信息,但是无害的。 – wujek 2015-02-09 15:42:37
对我来说,关闭连接并不容易。正如你在其他主题中提到的那样,开放助手应该被用作应用程序的单例。我可以在Application.onCreate()中启动它,但我无法阻止它。我可以在Pause/onResume活动中关闭并打开单身连接,但我觉得很不方便。不过,我可能会尝试去做。 – wujek 2015-02-09 15:46:16
@wujek:是的,我同意关闭'SQLiteDatabase'对于正确实现会相当复杂,事实上如果你不想在你的应用程序回到前台时重新查询所有游标,那么这可能不值得。如果你想这样做,你可以问一个关于如何正确实现它的新问题,我会提供一些提示。没有明确关闭数据库没有真正的问题(SQLite抱怨除外),所以你应该不用担心它,除非有这样的逻辑点。 – corsair992 2015-02-09 18:59:07
更改预写日志记录配置应该在'SQLiteOpenHelper'的'onConfigure()'回调方法与所有其他配置更改一起完成。 'SQLiteDatebase'甚至没有在构造函数中初始化,所以在那里做不起作用。我不明白为什么它应该输出该日志。你确定它记录在_that_点?你有一张名为“test”的表吗? – corsair992 2015-02-07 22:09:51
我说的方法是一个SQLiteOpenHelper方法,它有一堆检查,如果已经打开了一个数据库,它会应用一个新的设置。最后,它设置其内部字段:mEnableWriteAheadLogging = enabled;这在下次打开数据库时使用。我想你已经把它与另一种方法混合了:SQLiteDatabase.enable/disableWriteAheadLogging,它需要调用一个数据库实例。当这个方法被调用的时候,这个文档没有任何说明,而且在构造函数中调用时它确实可以工作(禁止日志错误)。 – wujek 2015-02-07 23:05:30
错误没有记录在启用WAL的时候,当第一条语句被执行时完成,在我的情况下是'select count(*)from test'。是的,我有一个'测试'表。奇怪的是,尽管错误被记录(只有这一行,没有堆栈跟踪没有),但整个应用程序工作正常。 – wujek 2015-02-07 23:08:06