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