android Sqlite多线程访问异常解决方案

在开发Android的程序的时候sqlite数据库是经常用到的;在多线程访问数据库的时候会出现这样的异常:java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.或 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: 或java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase:

这样的异常信息,Sqlite 自身是不支持多线程同时操作的,下面呢我们给出一个解决方案并列出一些项目中用到的代码。

我们会用到AtomicInteger,一个提供原子操作的Integer的类。因为Android 依托强大的jdk在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口,由此我们可以做一个DatabaseManager 这样的类,具体代码见下面的代码块:

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(SQLiteOpenHelper helper) {
        if (instance == null) {
            initializeInstance(helper);
        }
        return instance;
    }  

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

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

    public synchronized void closeDatabase() {  

        if(mOpenCounter.decrementAndGet() == 0) {
            // Closing database
            mDatabase.close();
        }
    }

在我们进行关闭数据库的时候判断

mOpenCounter.decrementAndGet() == 0 (更新器管理的给定对象的字段的当前值为0)的时候才正式关闭数据库,就不会出现上述异常。

用方式呢,在我们操作数据库逻辑代码中如下使用首相要取得
mDatabaseManager = DatabaseManager.getInstance(mContext);
对象
    /***
     * 判断表中是否有值
     */
    public boolean isExistTabValus() {
        boolean flag = false;
        SQLiteDatabase db = mDatabaseManager.getReadableDatabase();//获取一个可读的数据库对象
        Cursor curcor = null;
        try {
            curcor = db.rawQuery("select * from tab ", null);
            while (curcor.moveToNext()) {
                if (curcor.getCount() > 0) {
                    flag = true;
                }
            }
        } catch (Exception e) {
            Log.e(TAG, "isExistTabValus  error");
        } finally {
            if (curcor != null) {
                curcor.close();
            }
            mDatabaseManager.closeDatabase();//关闭数据库
        }
        return flag;
    }

上面提供一个使用方法,现在项目中使用这种方法关于数据库的操作从未没有出现并发的问题,大家可以尝试一下。

时间: 2024-10-02 00:32:55

android Sqlite多线程访问异常解决方案的相关文章

关于CoreData和SQLite多线程访问时的线程安全问题

http://www.jianshu.com/p/95db3fc4deb3 关于CoreData和SQLite多线程访问时的线程安全问题 数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两者都需要设置线程安全,在这里以FMDB来解释对SQLite的线程安全访问. 一:FMDB的线程安全:(以读取图片为例) 1.没有线程安全的执行方式: //****

CoreData和SQLite多线程访问时的线程安全

关于CoreData和SQLite多线程访问时的线程安全问题 数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两者都需要设置线程安全,在这里以FMDB来解释对SQLite的线程安全访问. 一:FMDB的线程安全:(以读取图片为例) 1.没有线程安全的执行方式: //************** 数据库保存图片 ******************/

CoreData和SQLite多线程访问时的线程安全问题

数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两者都需要设置线程安全,在这里以FMDB来解释对SQLite的线程安全访问. 一:FMDB的线程安全:(以读取图片为例) 1.没有线程安全的执行方式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

Android:加载Android Design Support Library异常解决方案

Google最新的兼容包Android Design Support Library增加了许多符合Material Design设计规范的控件,如Navigation View,Floating Action Button,SnackBar,Tabs,CoordinatorLayout,AppbarLayout,CollapsingToolbarLayout等. 笔者也及时更新了SDK,获得了Android Design Support Library支持包,但是在导入eclipse工程的过程中

kafka high-level consumer 多线程访问异常

在使用kafka high-level的consumer,使用多线程消费数据时报错,简单分析一下原因下载 ,ConsumerIterator取不到消息时会阻塞,并且将内部状态置为FAILED,当其他线程访问时就会抛出异常. Java代码   def hasNext(): Boolean = { if(state == FAILED)         //处于FAILED状态时,另外线程访问会直接异常 throw new IllegalStateException("Iterator is in 

无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)

1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.demo1" /> 上面targetPackage指定的包要和应用的package相同. (2)在清单文件中ap

android SQLite 批量插入数据慢的解决方案 (正对于不同的android api 版本)

SQLite,是一款轻型的数据库,被广泛的运用到很多嵌入式的产品中,因为占用的资源非常少,二其中的操作方式几乎和我们接触的数据库不多,甚至只有几百K的他自然会被需求者青睐,下面讲一下在这样的轻型数据库中怎么对他进行一些读写操作. 之前做选择联系人的时候出现如果一个手机里联系人超过2000的话,往数据库里面插入会非常耗时,不同的手机存储的条数不同,这个存储的数量和手机的内存有很大的关系,往往取决于手机内存,下面对于数据量大的情况来写一下sqlite的批量查询. SqLite 掺入数据有几种 第一种

Android Studio更改工程名异常解决方案 :can&#39;t rename root module

在修改Android Studio 中 project的名字时 ,提示 “can’t rename root module”. 这是因为Android Studio只能修改根目录内的所有文件,要修改project根目录名字,只能关闭Android Studio 在操作系统中修改文件夹名字. 具体步骤: 1.关闭Android Studio. 2.直接在操作系统中修改好名字. 3.重新import 新名字([NewName])的工程,这样就可以了,相当简单. 其实重新import后,Android

IOS 使用FMDB多线程访问数据库 及databaseislocked的问题

原理:文件数据库sqlite,同一时刻允许多个进程/线程读,但同一时刻只允许一个线程写.在操行写操作时,数据库文件被琐定,此时任何其他读/写操作都被阻塞,如果阻塞超过5秒钟(默认是5秒,能过重新编译sqlite可以修改超时时间),就报"database is locked"错误. 所以,在操作sqlite时,应该即时关闭连接:打开连接后,尽量减少非常费时的操作. 多线程同时访问数据库时,报数据库锁定的问题,错误信息是: Unknown error finalizing or reset