解决android数据库并发访问异常

我们在开发过程中很有可能要在多线程里处理数据库的操作,每一次创建SQLiteOpenHelper都会建立一个与数据库的连接,如果你在同一时间,两个以上的线程来对同一个线程进行写的操作的时候(读是没有问题的),那么其中会报以下异常:

android.database.sqlite.SQLiteDatabaseLockedException: database is locked
解决思路:既然是多线程这个大前提不能变,那么我们只需要确保所有的线程都是使用的同一个数据库就可以了

这就需要单例了:


public class CarConnectionHistoryDBOpenHelper extends SQLiteOpenHelper {

    public CarConnectionHistoryDBOpenHelper(Context context) {
        super(context, "carconnectionhistory", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table carconnectionhistory (_id integer primary key autoincrement, filename varchar(20),locpath varchar(20),remotepath varchar(20),progress varchar(20),max varchar(20),state varchar(20))");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

}

public class CarConnectionDao {
    private static CarConnectionHistoryDBOpenHelper helper;
    private static CarConnectionDao instance;
    private SQLiteDatabase mDatabase;

    public static CarConnectionDao getInstance() {
        if (instance == null) {
            synchronized (CarConnectionDao.class) {
                if (instance == null) {
                    helper = new CarConnectionHistoryDBOpenHelper(UIUtils.getContext());
                    instance = new CarConnectionDao();
                }
            }
        }
        return instance;
    }
这时候就解决了上述的异常问题,但是运行后会出现这个异常:

java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase
意思是你在尝试打开一个已经关闭的数据库,原因是我们只有一个数据库,当一个线程把这个数据库关闭的时候,另一个线程可能还在持有着数据库的连接,进行着写的操作,这显然是不行的

解决思路:数据库肯定是不能关闭的,什么时候关是关键,关的时候要保证现在的线程是最后一个持有数据库连接的,如果还有线程在持有该数据库连接,那就不用关闭。

思路有了,接下来实现:

AtomicInteger是android自带的一个控制自增长的类,我们分别创建两个方法,一个是打开数据库一个是关闭数据库,方便操作,在创建的时候让AtomicInteger自增1并且判断如果自增后为1,说明这是第一个线程,需要去创建一个数据库连接,而在关闭的时候先让AtomicInteger自减,然后去判断AtomicInteger的值,如果他为0,那么说明这是最后一个线程,这时候就关闭数据库的连接。

代码如下:

private AtomicInteger mOpenCounter = new AtomicInteger();//自增长类

//打开数据库方法
public synchronized SQLiteDatabase openDatabase() {
    if (mOpenCounter.incrementAndGet() == 1) {//incrementAndGet会让mOpenCounter自动增长1
        // Opening new database
        try {
            mDatabase = helper.getWritableDatabase();
        } catch (Exception e) {
            mDatabase = helper.getReadableDatabase();
        }
    }
    return mDatabase;
}

//关闭数据库方法
public synchronized void closeDatabase() {
    if (mOpenCounter.decrementAndGet() == 0) {//decrementAndGet会让mOpenCounter自动减1
        // Closing database
        mDatabase.close();
    }
}
现在你完全可以安全的使用数据库了,示例:

/**
 * 判断一个item是否存在
 */
public synchronized boolean find(String filename) {
    boolean result;
    mDatabase = getInstance().openDatabase();
    Cursor cursor = mDatabase.query("carconnectionhistory", null, "filename=?", new String[]{filename}, null, null, null);
    result = cursor.moveToNext();
    cursor.close();
    getInstance().closeDatabase();
    return result;
}

发布了10 篇原创文章 · 获赞 2 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览