启用(WAL)预写日志记录的Sqlite数据库锁定

时间:2017-01-09 05:04:07

标签: android sqlite

我的sqlite数据库正在运行锁定,即使我已启用WAL并且我在整个应用程序中使用了我的DbHelper的单例实例,如下所示:

public class DbHelper extends SQLiteOpenHelper { 

  private static final String mTAG = "DB_HELPER";
  private static DatabaseHelper sInstance;

  private static final String DATABASE_NAME = "database_name";
  private static final int DATABASE_VERSION = 1;

  public static synchronized DatabaseHelper getInstance(Context context) {

    if (sInstance == null) {
      sInstance = new DatabaseHelper(context.getApplicationContext());
    }
    return sInstance;
  }

  private DatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
  }
}

对于插入,我有以下功能:

public void insertToDb(String tableName, ContentValues contentValues) {
    SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
    sqLiteDatabase.enableWriteAheadLogging();
    sqLiteDatabase.beginTransactionNonExclusive();

    sqLiteDatabase.insert(tableName, null, contentValues);
    sqLiteDatabase.setTransactionSuccessful();
    sqLiteDatabase.endTransaction();
    sqLiteDatabase.close();
}

知道为什么会这样吗?

更新 我有一个asynctask,问题源于抛出attempt to re-open an already-closed object异常。接下来,我开始在我的logcat中得到以下错误:

#################################################################
Error Code : 5 (SQLITE_BUSY)
Caused By : The database file is locked.
(database is locked (code 5))
#################################################################
' Stack Trace: 'android.database.sqlite.SQLiteDatabaseLockedException: database is locked (code 5)
#################################################################
Error Code : 5 (SQLITE_BUSY)
Caused By : The database file is locked.
(database is locked (code 5))
#################################################################
at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:679)
at android.database.sqlite.SQLiteSession.beginTransactionUnchecked(SQLiteSession.java:319)
at android.database.sqlite.SQLiteSession.beginTransaction(SQLiteSession.java:298)
at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:510)
at android.database.sqlite.SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:445)
at com.ontheway.otw.entermarkets.helpers.database.OTWUserDb.updateOTWUserLocation(OTWUserDb.java:124)
at com.ontheway.otw.entermarkets.services.FusedLocationService.onLocationChanged(FusedLocationService.java:146)
at com.google.android.gms.internal.zzart$zzb$1.zza(Unknown Source)
at com.google.android.gms.internal.zzart$zzb$1.zzs(Unknown Source)
at com.google.android.gms.internal.zzaaz.zzb(Unknown Source)
at com.google.android.gms.internal.zzaaz$zza.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7325)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
'

2 个答案:

答案 0 :(得分:2)

SQLiteDatabase(由SQLiteOpenHelper包裹)是线程安全的(每个线程使用SQLiteConnectionPoolSQLiteSession)但你应该不关闭< / strong>它直到你完全完成数据库,对于大多数应用程序永远不会。这基本上就是链接文章所说的内容。

另一方面,您应确保交易始终结束,即使不成功,例如:

SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
sqLiteDatabase.enableWriteAheadLogging();
sqLiteDatabase.beginTransactionNonExclusive();
try {
    sqLiteDatabase.insert(tableName, null, contentValues);
    sqLiteDatabase.setTransactionSuccessful();
} finally {
    sqLiteDatabase.endTransaction();
}

答案 1 :(得分:0)

一个数据库连接对象等于一个事务,因此多个线程必须使用多个数据库连接。

或者,您可以确保没有两个线程同时访问数据库。但是,将synchronized放在getInstance()上是不够的;您必须使用共享锁锁定所有数据库代码(例如,整个insertToDb()函数)。