为什么引用计数在我的SQLiteDatabase中不起作用?

时间:2018-01-26 03:26:43

标签: android android-sqlite

我读到SQLiteDatabase使用引用计数来管理同时查询同一个数据库的两个线程,但它对我不起作用。

  • 我的两个帖子都通过在SQLiteDatabase的同一个实例上调用getWriteableDatabase()来获取SQLiteOpenHelper个对象。
  • 两个线程同时使用SQLiteDatabase.query()运行查询。
  • 我没有使用交易。
  • 在每个查询结束时,相应的线程调用SQLiteOpenHelper.close()
  • 第一个线程关闭数据库后,第二个线程在调用SQLiteDatabase.query()时抛出此异常:
      

    java.lang.IllegalStateException:尝试重新打开已经关闭的   对象:SQLiteDatabase:   /data/user/0/com.comet.android.TypeSmart/databases/en.dic

我也尝试拨打SQLiteDatabase.close()而不是SQLiteOpenHelper.close(),但它没有帮助。 :(

引用计数是不是应该阻止这个?

1 个答案:

答案 0 :(得分:0)

关于nfrolov说的话:

  

Android已在内部实现引用计数。基本上,无论何时对SQLiteDatabase执行任何操作,它都会递增计数器,当您完成后,它会递减计数器。 完成所有操作后,数据库只会自行关闭。我完全没有理由再次猜测这个系统。只是不要关闭数据库。你必须关闭游标。

参考:https://nfrolov.wordpress.com/2014/08/16/android-sqlitedatabase-locking-and-multi-threading/

但是不关闭数据库可能会导致:

Leak found
Caused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed

有一个解决方案,你将实现一个AtomicInteger,你将在其中计算你打开数据库的次数,然后在你即将关闭时递减它,当它达到0时,就是时间你要关闭它。

public class DatabaseManager {

private AtomicInteger mOpenCounter = new AtomicInteger();

private static DatabaseManager instance;
private static SQLiteOpenHelper mDatabaseHelper;
private SQLiteDatabase mDatabase;

public static synchronized void initializeInstance(SQLiteOpenHelper helper) {
    if (instance == null) {
        instance = new DatabaseManager();
        mDatabaseHelper = helper;
    }
}

public static synchronized DatabaseManager getInstance() {
    if (instance == null) {
        throw new IllegalStateException(DatabaseManager.class.getSimpleName() +
                " is not initialized, call initializeInstance(..) method first.");
    }

    return instance;
}

public synchronized SQLiteDatabase openDatabase() {
    if(mOpenCounter.incrementAndGet() == 1) {
        // Opening new database
        mDatabase = mDatabaseHelper.getWritableDatabase();
    }
    return mDatabase;
}

public synchronized void closeDatabase() {
    if(mOpenCounter.decrementAndGet() == 0) {
        // Closing database
        mDatabase.close();

    }
}
}

据Dmytro Danylyk说:

  

每次需要数据库时,都应该调用DatabaseManager类的openDatabase()方法。在这个方法中,我们有一个计数器,它指示数据库的打开次数。如果它等于1,则意味着我们需要创建新的数据库。如果没有,则已创建数据库。

     

在closeDatabase()方法中也是如此。每当我们称这种方法时,计数器就会减少;每当它变为零时,我们正在关闭数据库。

完整示例参考:https://blog.lemberg.co.uk/concurrent-database-access