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

转载:http://blog.csdn.net/zj695469296/article/details/50586994

我们在开发过程中很有可能要在多线程里处理数据库的操作,每一次创建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;
}

猜你喜欢

转载自blog.csdn.net/wangwasdf/article/details/77711613