最近在Android项目中因为涉及到多线程访问数据库SQLite而出现SQLiteDatabaseLockedException异常,经过查找资料终于找到解决方法:避免数据库接口被多个线程同时访问。
具体措施有:
1、数据库接口采取单例模式
- public class DBOpenHelper extends SQLiteOpenHelper {
- private static final String DB_FILENAME = "llhome.db";
- private static final int DB_VERSION = 1;
- private static DBOpenHelper helper = null;
- public static DBOpenHelper getInstance(Context context){
- if (helper == null){
- synchronized (DBOpenHelper.class) {
- if (helper == null){
- DBOpenHelper temp = new DBOpenHelper(context);
- helper = temp;
- }
- }
- }
- return helper;
- }
public class DBOpenHelper extends SQLiteOpenHelper {
private static final String DB_FILENAME = "llhome.db";
private static final int DB_VERSION = 1;
private static DBOpenHelper helper = null;
public static DBOpenHelper getInstance(Context context){
if (helper == null){
synchronized (DBOpenHelper.class) {
if (helper == null){
DBOpenHelper temp = new DBOpenHelper(context);
helper = temp;
}
}
}
return helper;
}
2、所有访问数据的接口用synchronized加锁:
- boolean android.database.sqlite.SQLiteDatabase.isDbLockedByOtherThreads();
- boolean android.database.sqlite.SQLiteDatabase.isDbLockedByCurrentThread();
boolean android.database.sqlite.SQLiteDatabase.isDbLockedByOtherThreads();
boolean android.database.sqlite.SQLiteDatabase.isDbLockedByCurrentThread();
3、光是给接口加锁还不行,因为 synchronized 关键词只能锁定程序块,但是我们真正需要锁的是数据库,好在SQLiteDataBase提供了两个接口,用于检测数据库当时是否被锁定:
所以我们在访问之前还需要增加判断,如果数据库当前被锁定,就等待一会再去访问。
- public synchronized void insert(InstallModel info) {
- while (db.isDbLockedByOtherThreads() || db.isDbLockedByCurrentThread()){
- Log.w(Tag, "insert === db is locked by other or current threads!");
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- db.execSQL("INSERT INTO install(pkg, pay, install, inApply, flag, attributes, id, introduction, name, smallPicUrl," +
- "bigPicUrl, categoryId, sourceUrl, pid, cid, built_in, applyMode) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?)",
- new Object[] {"" + info.getPkg(), "" + info.getPay(), "" + info.getInstall(), "" + info.getIsApply(), "" + info.getFlag(),
- "" + info.getAttributes(), "" + info.getId(), "" + info.getIntroduction(), "" + info.getName(), "" + info.getSmallPicUrl(),
- "" + info.getBigPicUrl(), "" + info.getCategoryId(), "" + info.getSourceUrl(), "" + info.getPid(), "" + info.getCid(),
- "" + info.getBuilt_in(), "" + info.getApplyMode()
- });
- }
public synchronized void insert(InstallModel info) {
while (db.isDbLockedByOtherThreads() || db.isDbLockedByCurrentThread()){
Log.w(Tag, "insert === db is locked by other or current threads!");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
db.execSQL("INSERT INTO install(pkg, pay, install, inApply, flag, attributes, id, introduction, name, smallPicUrl," +
"bigPicUrl, categoryId, sourceUrl, pid, cid, built_in, applyMode) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?)",
new Object[] {"" + info.getPkg(), "" + info.getPay(), "" + info.getInstall(), "" + info.getIsApply(), "" + info.getFlag(),
"" + info.getAttributes(), "" + info.getId(), "" + info.getIntroduction(), "" + info.getName(), "" + info.getSmallPicUrl(),
"" + info.getBigPicUrl(), "" + info.getCategoryId(), "" + info.getSourceUrl(), "" + info.getPid(), "" + info.getCid(),
"" + info.getBuilt_in(), "" + info.getApplyMode()
});
}