SQLite数据库在多个线程中被访问

6
考虑以下情况:我有一个“服务(Service)”,它在“AsyncTask”中写入数据库。我的活动(Activity)从数据库中读取数据(考虑UI线程以简化问题)。我使用“SQLiteOpenHelper”访问数据库。我在Application onCreate()中创建单个实例,然后在服务和活动中获取它。是否有可能出现数据库“死锁(dead locked)”的情况?以前,我使用ContentProvider进行此类操作。尽管它基于使用单个“SQLiteOpenHelper”实例,但我决定通过排除“ContentProvider”来简化我的项目。
考虑代码:
public class App extends Application {

    private OpenHelper openHelper;

    @Override
    public void onCreate(){
        super.onCreate();
            openHelper=new OpenHelper();
    }

        public OpenHelper getHelper(){
            return openHelper;
        }
}

在Activity中:

OpenHelper helper=(App)getApplication().getHelper();
SQLiteDatabase db=helper.getReadableDatabase();
// Do reading

在Service内部,开启一个独立的线程:

OpenHelper helper=(App)getApplication().getHelper();
SQLiteDatabase db=helper.getWritableDatabase();
//Do writing

这个功能是否安全?

更新 这里 可能是解决方案,但不确定如何使用。

5个回答

7
晚了,回答晚了。你完全没问题。实际上这是正确的方法。请查看我的博客文章:http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection/。深入研究我的个人资料。这里有很多示例。ContentProvider只是很多开销,除非你在应用程序外共享数据。事务可以加快速度并(显然)提高一致性,但不是必需的。只需在应用程序中使用一个SqliteOpenHelper即可安全。

@seb 你可以想你喜欢的,但是你错了。抱歉。我已经开发了许多应用程序,持续数年,拥有数百万用户。它有效。 - Kevin Galligan
@seb 好的。少一点傲慢。HELPER是单例模式,而不是DATABASE。HELPER保持一个单一的DATABASE实例。请参见此处:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/database/sqlite/SQLiteOpenHelper.java - Kevin Galligan
@seb 如果你只保留一个辅助程序,那就没问题了。我没有其他声明。 - Kevin Galligan
@seb 但是,如果你有新的信息,我总是很感兴趣。如果你在纽约附近并且想要演讲,请告诉我。我组织了一个大型聚会 ;) - Kevin Galligan
你需要@schwiz ;) - seb
显示剩余3条评论

2
我的看法是:这不安全。
为了处于更安全的位置,您应该使用SQL事务。从beginTransaction()beginTransactionNonExclusive()开始,以endTransaction()结束。就像这里所示的那样。

beginTransactionNonExclusive() 给我一个错误,说它是针对 API11 及以上版本的。但我的应用程序最低支持 API 是 10。有没有其他方法可以使用 SQLite 的 IMMEDIATE 模式? - Maulik Sheth

1
这是我的解决方案 我创建了一个类和一个私有静态对象来同步所有的数据库访问。
public class DBFunctions {
// ...
private static Object lockdb = new Object();


/**
 * Do something using DB
 */
public boolean doInsertRecord(final RecordBean beanRecord) {
    // ...
    boolean success = false;

    synchronized (lockdb) {
              // ...
              // 
              // here ... the access to db is in exclusive way
              // 

              // ...
      final SQLiteStatement statement = db.compileStatement(sqlQuery);

        try {
            // execute ...
            statement.execute(); 
            statement.close();

            // ok
            success = true;
        } catch (Exception e) {
            // error
            success = false;
        }
            }

       return success;
    }

}

我尝试使用异步任务,它可以正常工作。 我希望这是解决问题的正确方法。 还有其他建议吗?

同时运行三个AsyncTasks,所有任务都向一个表中插入许多行数据。(所有任务都写入同一张表中。)看起来任务队列没有问题,也没有抛出错误。这个解决方案对我很有效。但我仍然想知道这个解决方案是否具有死锁安全性。有任何意见吗? - BenjaminButton

0

好问题。我的第一反应是不安全的。然而,根据SQLite文档,SQLite可以在3种模式下使用。默认模式是“串行”模式:

串行。在串行模式下,SQLite可以被多个线程安全地使用,没有任何限制。

因此,我认为它在Android上编译成了串行模式。


0

我在寻找其他东西时看到了这个问题。这个问题看起来可以通过使用ContentProvider来高效地解决。这样,Activity和Service都可以使用内容提供程序,这将解决数据库争用问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接