我使用这个类来管理与底层sqlite
Database的连接
public class BasicDataSource { protected DatabaseHandler dbHelper; protected volatile sqliteDatabase readable_database; protected volatile sqliteDatabase writable_database; protected Object read_lock = new Object(); protected Object write_lock = new Object(); protected Context context; protected BasicDataSource(Context ctx) { dbHelper = DatabaseHandler.getInstance(ctx); getReadableDatabase(); dbHelper.onCreate(getWritableDatabase()); this.context = ctx; } public synchronized void close() { dbHelper.close(); } protected void closeInsertHelpers(InsertHelper... helpers) { for (InsertHelper ih : helpers) { if (ih != null) ih.close(); } } protected sqliteDatabase getReadableDatabase() { synchronized (read_lock) { if (readable_database == null || !readable_database.isOpen()) { readable_database = dbHelper.getReadableDatabase(); } return readable_database; } } protected sqliteDatabase getWritableDatabase() { synchronized (write_lock) { if (writable_database == null || !writable_database.isOpen()) { writable_database = dbHelper.getWritableDatabase(); } return writable_database; } } protected synchronized void open() throws sqlException { getReadableDatabase(); getWritableDatabase(); } }
它包含两个锁,一个用于读取,第二个用于写入.
但我还是偶尔得到这样的例外:
java.lang.RuntimeException: An error occured while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:299) at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) at java.util.concurrent.FutureTask.setException(FutureTask.java:124) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java.lang.Thread.run(Thread.java:856) Caused by: android.database.sqlite.sqliteDatabaseLockedException: database is locked (code 5):,while compiling: PRAGMA journal_mode at android.database.sqlite.sqliteConnection.nativePrepareStatement(Native Method) at android.database.sqlite.sqliteConnection.acquirePreparedStatement(sqliteConnection.java:882) at android.database.sqlite.sqliteConnection.executeForString(sqliteConnection.java:627) at android.database.sqlite.sqliteConnection.setJournalMode(sqliteConnection.java:313) at android.database.sqlite.sqliteConnection.setWalModeFromConfiguration(sqliteConnection.java:287) at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:215) at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:193) at android.database.sqlite.sqliteConnectionPool.openConnectionLocked(sqliteConnectionPool.java:463) at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:185) at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:177) at android.database.sqlite.sqliteDatabase.openInner(sqliteDatabase.java:804) at android.database.sqlite.sqliteDatabase.open(sqliteDatabase.java:789) at android.database.sqlite.sqliteDatabase.openDatabase(sqliteDatabase.java:694) at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:804) at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221) at android.database.sqlite.sqliteOpenHelper.getDatabaseLocked(sqliteOpenHelper.java:224) at android.database.sqlite.sqliteOpenHelper.getWritableDatabase(sqliteOpenHelper.java:164) at com.mycompany.myapplication.sql.BasicDataSource.getWritableDatabase(BasicDataSource.java:57) at com.mycompany.myapplication.sql.datasources.SomeDataSource.fillUpDatabaseMethod(SomeDataSource.java:264) at com.mycompany.myapplication.sql.datasources.SomeDataSource.renewCacheMethod(SomeDataSource.java:560) at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:315) at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:1) at android.os.AsyncTask$2.call(AsyncTask.java:287) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) ... 4 more android.database.sqlite.sqliteDatabaseLockedException: database is locked (code 5):,while compiling: PRAGMA journal_mode at android.database.sqlite.sqliteConnection.nativePrepareStatement(Native Method) at android.database.sqlite.sqliteConnection.acquirePreparedStatement(sqliteConnection.java:882) at android.database.sqlite.sqliteConnection.executeForString(sqliteConnection.java:627) at android.database.sqlite.sqliteConnection.setJournalMode(sqliteConnection.java:313) at android.database.sqlite.sqliteConnection.setWalModeFromConfiguration(sqliteConnection.java:287) at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:215) at android.database.sqlite.sqliteConnection.open(sqliteConnection.java:193) at android.database.sqlite.sqliteConnectionPool.openConnectionLocked(sqliteConnectionPool.java:463) at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:185) at android.database.sqlite.sqliteConnectionPool.open(sqliteConnectionPool.java:177) at android.database.sqlite.sqliteDatabase.openInner(sqliteDatabase.java:804) at android.database.sqlite.sqliteDatabase.open(sqliteDatabase.java:789) at android.database.sqlite.sqliteDatabase.openDatabase(sqliteDatabase.java:694) at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:804) at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:221) at android.database.sqlite.sqliteOpenHelper.getDatabaseLocked(sqliteOpenHelper.java:224) at android.database.sqlite.sqliteOpenHelper.getWritableDatabase(sqliteOpenHelper.java:164) at com.mycompany.myapplication.sql.BasicDataSource.getWritableDatabase(BasicDataSource.java:57) at com.mycompany.myapplication.sql.datasources.SomeDataSource.fillUpDatabaseMethod(SomeDataSource.java:264) at com.mycompany.myapplication.sql.datasources.SomeDataSource.renewCacheMethod(SomeDataSource.java:560) at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:315) at com.mycompany.myapplication.activities.lists.ListsActivity$Worker.doInBackground(ListsActivity.java:1) at android.os.AsyncTask$2.call(AsyncTask.java:287) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) at java.util.concurrent.FutureTask.run(FutureTask.java:137) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java.lang.Thread.run(Thread.java:856)
这意味着,当尝试在getWritableDatabase中获取锁定时,数据库被某种方式锁定.
解决方法
在sqlite中,可以有任意多的读者,但任何作家都会阻止所有其他读者和作家.
您必须为读者和作家使用单一的锁.
请注意,只要您实际访问数据库,锁必须保持.
如果要支持多个读取器,请使用实现ReadWriteLock
的锁,例如ReentrantReadWriteLock
.这样的东西:
class MyData { private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); public Data ReadSomething(int id) { r.lock(); try { Cursor c = readableDatabase.query(...); return c.getString(0); } finally { r.unlock(); } } public void ChangeSomething(int id,int value) { w.lock(); try { writeableDatabase.update(...); } finally { w.unlock(); } } }