您的位置:首页 > 移动开发 > Android开发

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

2016-01-26 14:59 465 查看
我们在开发过程中很有可能要在多线程里处理数据库的操作,每一次创建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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: