2015-02-07 116 views
2

當我打電話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 
+0

更改預寫日誌記錄配置應該在'SQLiteOpenHelper'的'onConfigure()'回調方法與所有其他配置更改一起完成。 'SQLiteDatebase'甚至沒有在構造函數中初始化,所以在那裏做不起作用。我不明白爲什麼它應該輸出該日誌。你確定它記錄在_that_點?你有一張名爲「test」的表嗎? – corsair992 2015-02-07 22:09:51

+0

我說的方法是一個SQLiteOpenHelper方法,它有一堆檢查,如果已經打開了一個數據庫,它會應用一個新的設置。最後,它設置其內部字段:mEnableWriteAheadLogging = enabled;這在下次打開數據庫時使用。我想你已經把它與另一種方法混合了:SQLiteDatabase.enable/disableWriteAheadLogging,它需要調用一個數據庫實例。當這個方法被調用的時候,這個文檔沒有任何說明,而且在構造函數中調用時它確實可以工作(禁止日誌錯誤)。 – wujek 2015-02-07 23:05:30

+0

錯誤沒有記錄在啓用WAL的時候,當第一條語句被執行時完成,在我的情況下是'select count(*)from test'。是的,我有一個'測試'表。奇怪的是,儘管錯誤被記錄(只有這一行,沒有堆棧跟蹤沒有),但整個應用程序工作正常。 – wujek 2015-02-07 23:08:06

回答

2

經過一番實驗,看起來由於某種原因,SQLite將表的緩存列表保存爲與打開的連接關聯的元數據的一部分。創建新表只會更新用於執行此操作的連接上的緩存。如果使用連接對未包含在緩存元數據中的表執行某些操作,那麼即使操作本身成功執行(並且隨後更新緩存),它也會抱怨該表不存在。

通過SQLiteDatabase使用的連接池目前只允許一個連接讀取和如果未啓用預寫日誌,大概是爲了避免因執行讀操作錯誤寫操作,而一個作家上具有獨佔鎖數據庫。如果啓用預寫式日誌記錄,則除了主寫連接之外,它還允許至少一個單獨的讀連接(讀連接的確切限制由系統屬性定義)。

SQLiteOpenHelper打開讀取連接以獲取版本信息之前打開用於數據庫初始化和升級/降級的寫入連接。如果預寫式日誌記錄未啓用,則它們都是相同的連接。但是,如果預寫日誌記錄在初始化之前啓用,則讀連接的高速緩存不會反映在初始化過程中執行的任何結構更改(並且SQLite會在執行第一個查詢時在日誌中抱怨)。這可以通過從初始化完成後調用的onOpen()方法啓用預寫日誌記錄來解決。

至於日誌約架回收,這是由事實SQLite的檢查點,並刪除WAL文件時,所有的連接被關閉造成的。如果持有連接的進程在沒有明確關閉的情況下終止,那麼當新連接隨後打開時執行此清理,並且SQLite會對此進行投訴。如果您在應用程序移至後臺時關閉SQLiteDatabase,則應解決此問題。另一方面,如果您在整個應用程序中與數據庫進行交互,那麼可能會出現問題並且難以實施,我不建議這樣做。

+0

謝謝。所以我只會考慮第一個錯誤信息(關於缺少的表)是一個虛假的信息,這是一個令人討厭的信息,但是無害的。 – wujek 2015-02-09 15:42:37

+0

對我來說,關閉連接並不容易。正如你在其他主題中提到的那樣,開放助手應該被用作應用程序的單例。我可以在Application.onCreate()中啓動它,但我無法阻止它。我可以在Pause/onResume活動中關閉並打開單身連接,但我覺得很不方便。不過,我可能會嘗試去做。 – wujek 2015-02-09 15:46:16

+1

@wujek:是的,我同意關閉'SQLiteDatabase'對於正確實現會相當複雜,事實上如果你不想在你的應用程序回到前臺時重新查詢所有遊標,那麼這可能不值得。如果你想這樣做,你可以問一個關於如何正確實現它的新問題,我會提供一些提示。沒有明確關閉數據庫沒有真正的問題(SQLite抱怨除外),所以你應該不用擔心它,除非有這樣的邏輯點。 – corsair992 2015-02-09 18:59:07