`

Android Sqlite Database locked的问题

阅读更多

        SQLite实质上是将数据写入一个文件,通常情况下,在应用的包名下面都能找到xxx.db的文件,拥有root权限的手机,可以通过adb shell,看到data/data/packagename/databases/xxx.db这样的文件。

        我们可以得知SQLite是文件级别的锁:多个线程可以同时读,但是同时只能有一个线程写。Android提供了SqliteOpenHelper类,加入Java的锁机制以便调用。

        如果多线程同时读写(这里的指不同的线程用使用的是不同的Helper实例),后面的就会遇到android.database.sqlite.SQLiteException: database is locked这样的异常。
        对于这样的问题,解决的办法就是keep single sqlite connection保持单个SqliteOpenHelper实例,同时对所有数据库操作的方法添加synchronized关键字。

 

 

在项目开发过程中,由于数据库的架构设计问题,会很容易出现以下异常:

android.database.sqlite.SQLiteException: <wbr>database <wbr>is <wbr>locked

注意:

   (1)这里的异常信息仅仅是android.database.sqlite.SQLiteException: database is locked, 在我研发过程中,还抛出了类似这样的异常信息。该异常是不可以被捕获的。           (2)android.database.sqlite.SQLiteException: database is locked一些信息)。该异常是可以被捕获的。

   这两种异常显然都是数据库被锁异常,但是异常信息不同,说明引起异常的原因也不同。

 

   起初我认为这是由于在我操作数据库的方法前面加了synchronized 的缘故,仔细想想,加这个是避免同时两个线程去写数据库,在逻辑上是完全这确的。去掉之后多线程访问数据库时,会出现数据库关闭的异常,这是由于线程B访问完数据库时,将数据库关闭,线程A再访问数据库引起,它们使用的是同一个数据库对象。

 

    之后,我又查了很多资料,很多人提到了使用继承ContentProvider的方式,来解决该异常。

    但是这种方式有2个弊端:

      1.使用继承ContentProvider方式,会将项目的数据库暴露给第三方。一般系统级应用,如存储联系人,        存储短信的数据库才有必要暴露给第三方。

      2.使用方式不如直接继承SQLiteOpenHelper对象简单。

 

Android技术文档提到: A content provider is only required if you need to share data between multiple applications. For example, the contacts data is used by multiple applications and must be stored in a content provider. If you don't need to share data amongst multiple applications you can use a database directly via SQLiteDatabase. 

    

    如果需要在多个应用之间共享数据的话,ContentProvider方式才应该被使用。例如:联系人数据被多个应用使用,那么它就应该使用在ContentProvider方式存储。如果你不需要共享数据,那么仅仅使用SQLiteDatabase. 数据库就可以了。

 

    现在不使用继承ContentProvider的方式,我们该如何解决以上的异常呢?

    The reason a ContentProvider solves the problem is because it usually uses one singleSQLiteOpenHelper which means that there is only one connection to the database and the underlyingSQLiteDatabase takes care of the locking. You don't need a ContentProvider - just make sure you don't write to the DB using 2 different db connections. 

 

     A. ContentProvider能解决此问题的原因是它只用一个单一的SQLiteOpenHelper对象,也就是说在app中仅仅有一个“数据库连接” 连接着数据库并且由SQLiteOpenHelper中的SQLiteDatabase负责维护数据库的锁

 

    B. 你不需要一个ContentProvider - 只要确保不要用2个不同的“数据库连接”去连接数据库就可以了。

     

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics