the*_*ger 10 java sqlite multithreading android
注意:请不要将此问题标记为重复.我已经经历了几个类似的问题,但找不到满意的答案.
我一直在研究使用Sqlite数据库的应用程序.我们遵循单例模式,确保我们只能在整个应用程序中创建一个辅助类实例.
public class CustomSqliteHelper extends SQLiteOpenHelper {
public static CustomSqliteHelper getInstance(Context context) {
if (instance == null) {
synchronized (CustomSqliteHelper.class) {
if (instance == null) {
instance = new CustomSqliteHelper(context);
}
}
}
return instance;
}
}
Run Code Online (Sandbox Code Playgroud)
但有时应用程序崩溃了SQLiteDatabaseLockedException.我理解当多个线程/进程尝试一次写入数据库时会出现此异常.即使一个线程/进程在写操作仍在进行时尝试读取数据库,也会抛出此异常.
所以我一直在阅读很多关于这个以及防止这种情况发生的可能方法.很多帖子建议使用ContentProvider而不是直接扩展SqliteOpenHelper类和对数据库对象执行操作.在阅读其中一篇帖子时,这篇文章提到在使用Content Provider时,您不需要手动处理多线程环境.
虽然ContentProvider缺乏线程安全性,但通常您会发现在防止潜在的竞争条件方面您无需采取进一步行动.规范示例是您的ContentProvider由SQLiteDatabase支持的时间; 当两个线程同时尝试写入数据库时,SQLiteDatabase将自行锁定,确保一个等待直到另一个完成.每个线程都将获得对数据源的互斥访问,从而确保满足线程安全性.
以上引用似乎令人困惑,因为首先它提到ContentProvider不支持线程安全.但他总结说,应用程序开发人员不需要做任何事情来实现并发.
另外,如果我选择使用SqliteOpenHelper,那么防止这些崩溃的最佳方法是什么?我一直在考虑为每个db操作使用锁.
public class CustomSqliteHelper extends SQLiteOpenHelper {
private String lock = "lock";
public void insert(){
synchronized(lock){
// Do the insert operation here.
}
}
public void update(){
synchronized(lock){
// Do the update operation here.
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我的一个团队成员建议我不要这样做,因为Java锁很贵.
在经历了Github上最受欢迎的项目之一后,我发现开发人员建议将每个数据库操作包装在一个事务中.
public void insert(ContentValues values) {
// Create and/or open the database for writing
SQLiteDatabase db = getWritableDatabase();
// It's a good idea to wrap our insert in a transaction. This helps with performance and ensures
// consistency of the database.
db.beginTransaction();
try {
// The user might already exist in the database (i.e. the same user created multiple posts).
db.insertOrThrow(TABLE_POSTS, null, values);
db.setTransactionSuccessful();
} catch (Exception e) {
Log.d(TAG, "Error while trying to add post to database");
} finally {
db.endTransaction();
}
}
Run Code Online (Sandbox Code Playgroud)
我真的不确定这是否可以阻止Lock异常?这似乎更像是一个以绩效为导向的步骤.
所以在阅读完所有博客和教程之后,我仍然感到困惑.我的主要问题是
更新:根据@Mustanar的回答,似乎SQLiteDatabase负责锁定机制.这意味着如果您正在执行写操作,则数据库将被锁定.但同时,如果某个其他线程尝试执行写操作,那么第二个操作是否会等待直到锁被释放或者是否会抛出android.sqlite.database.SQLiteDatabaseLockedException异常?
更新2:对这个问题给予赏金,因为答案似乎仍然不清楚.我只使用Helper类的一个实例.但仍然得到这个错误.
PS:感谢您提出这么长的问题.
使用Singleton模式来实例化SQLiteOpenHelper,因此在整个应用程序中应该存在一个单例实例。这将确保不会发生泄漏,并使您的生活更轻松,因为它消除了在编写代码时忘记关闭数据库的可能性。它还将确保在整个应用程序中安全访问数据库。
此外,您不必实现自己的锁定机制。SQLiteDatabase保持锁定机制。因此,在特定时间只有一个事务在进行,所有其他事务都将Queue使用该Sigleton.getInstance()方法。确保数据库的单一访问点。
此外,在这种方法中,您不必关闭数据库连接,因为一旦事务完成,SQLiteDatabase 将释放所有引用。SoCustomSQLiteHelper.getInstance()应该在您想要执行 CRUD 操作并删除锁定 mecansim 时使用。
更多信息,请浏览博客http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html并查看评论。
希望这可以帮助。