2011-06-03 80 views
6

请考虑以下内容:我有Service,它在AsyncTask中写入数据库。我的Activity从数据库读取数据(为简单起见,考虑UI线程)。我使用SQLiteOpenHelper访问数据库。我在Application onCreate()中创建单个实例,然后在服务和活动中获取它。有没有可能让我的数据库'死锁'?以前,我使用ContentProvider进行这些操作。虽然它基于使用单个的SQLiteOpenHelper实例,但我决定通过排除ContentProvider来简化我的项目。从多个线程访问的SQLite数据库

考虑代码:

public class App extends Application { 

    private OpenHelper openHelper; 

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

     public OpenHelper getHelper(){ 
      return openHelper; 
     } 
} 

在活动时间:

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

而且里面的贡献莫过于,在单独的线程:

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

难道是安全的?

UPDThis可能是解决方案,但不知道如何使用它。

回答

0

好问题。我的第一个想法是它不安全。但是,根据SQLite docs,SQLite可以在3种模式下使用。默认模式是“序列化”模式:

序列化。在串行模式,SQLite的 可以安全地使用多线程 没有限制

所以我认为这是在Android上的序列化模式进行编译。

2

我的投注:这是不安全的。

要处于更安全的位置,您应该使用SQL事务。从beginTransaction()beginTransactionNonExclusive()开始,并以endTransaction()结束。 Like shown here

+0

beginTransactionNonExclusive()给我错误,它为上面的api11。但我的应用程序min api是10.任何其他方式使用sqlite与IMMEDIATE模式? – 2013-10-02 13:29:52

1

这是我的解决方案 我创建了一个类和私有静态对象syncronize所有DB访问

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; 
    } 

}

我使用异步任务tryed,它工作正常。 我希望是解决问题的正确方法。

其他建议???

+0

同时运行三个AsyncTasks,全部插入许多行到一个表中。 (全部写入同一张表)看起来任务队列并且因此没有错误被抛出。这个解决方案适用于我。我仍然想知道这个解决方案是否是死锁安全的。有什么意见? – BenjaminButton 2013-10-10 10:17:24

+0

经过一些更多的测试数据库锁定错误再次出现... – BenjaminButton 2013-10-10 10:45:18

0

刚看到这个,而我正在寻找别的东西。 此问题看起来像使用ContentProvider可以有效解决。这样,活动以及服务都可以使用内容提供者,并将处理Db争用问题。

7

迟到,迟到的答案。你完全没问题。实际上,这是正确的做法。看我的博客文章:http://touchlabblog.tumblr.com/post/24474750219/single-sqlite-connection/。在这里挖掘我的个人资料。很多这样的例子。除非您在应用程序之外共享数据,否则ContentProvdier只是很大的开销,并不需要。事务处理很好地加速了事件并(显然)提高了一致性,但并不需要。

只需在您的应用中使用一个SqliteOpenHelper,您就安全了。

+0

博客文章关闭 – seb 2012-09-24 23:28:04

+0

@seb编辑答案。几个月前移动了博客。也看看sqlite锁定帖子:http://touchlabblog.tumblr.com/post/24474398246/android-sqlite-locking。他们在这里的关键是Android在Java-land中为你做了线程锁定,但只在单个实例上。多个会打破对方。另外,在文章中说,在UI线程中进行数据库读取。请注意:不要这样做。永远。 – 2012-09-26 04:53:55

+0

@KevinGalligan我已经挖掘了SQLiteDatabase和Helper的源代码,我相信你错了。 Database对象创建一个SQLiteStatement对象,该对象又使用SQLiteSession,每个线程都将拥有自己的SQLiteSession。它特别在SQLiteSession中说javadoc类不是线程安全的。好奇是什么让你说这个,因为我真的希望你是对的... – schwiz 2013-10-13 18:31:29