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

 

引用\[1\]:根据官方文档,从3.3.1版本开始,SQLite支持多线程并发访问数据库,但要求设置为SQLITE_THREADSAFE模式。每个数据库连接只能在一个线程中使用,不可多个线程共用一个数据库连接。\[1\]引用\[2\]:SQLite默认情况下只支持单个数据库连接操作,多连接并发操作时会出问题,需要开启wal模式才能进行多项城并发读操作操作仍不能并发。\[2\]根据这些信息,可以得出以下结论:在SQLite中,多线程操作数据库有两种解决方案。第一种是多线程读和,只使用一个数据库连接,这种情况下由于使用的是同一个数据库连接,SQLite内部有锁机制,不会出现异常。但是这种多线程操作并不是真正的并发操作,由于锁机制的存在,仍然是阻塞的。第二种是多线程读和单线程,每个线程使用独立的数据库连接,并开启wal模式。这种情况下可以实现多线程并发读操作,但操作仍然只能单线程进行。如果多个线程同时入(每个线程使用独立的数据库连接),就会出现问题。\[2\]在实际测试中,方案一的用时是方案二的两倍多。\[2\]关于方案一的具体实现,有两种方式:一是开启一个数据库连接永不关闭,二是自己编一个管理类来实现。\[2\]要开启wal模式,可以使用SQLiteDatabase.enableWriteAheadLogging()方法。\[2\]在多线程操作SQLite时,可能会遇到数据库被锁定的问题,这可能是由于子线程执行的query函数有问题导致的。\[3\] #### 引用[.reference_title] - *1* [SQLite多线程应用与iOS开发](https://blog.csdn.net/pcliuguangtao/article/details/8123473)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SQLite多线程并发操作](https://blog.csdn.net/a987687115/article/details/84566282)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Android SQLite多线程和线程同步源码分析](https://blog.csdn.net/z979451341/article/details/79593551)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值