Исключение SQLite: проблема блокировки базы данных

У меня возникла проблема с моей базой данных SQLite внутри приложения для Android. Кажется, что это происходит каждый раз, и я не могу воспроизвести его, но это отчет, который дает Android Market.

В основном у меня есть первая активность заставки, которая начинается с проверки наличия всех необходимых данных в базе данных. Если нет, он установит данные в асинхронном потоке и закроет соединение db.

Затем и только тогда можно запустить основное действие, которое также открывает и считывает / записывает базу данных.

Этот код выполняется из метода onCreate активности заставки:

dbWord = new WordDBAdapter(this, myUI); dbWord.open(); if (dbWord.isDataInstalled()) { dbWord.close(); databaseInstalled = true; clickToStartView.setText(myUI.PRESS_TO_START); clickToStartView.startAnimation(myBlinkAnim); } else { // If not, try to install in asynchronous thread progressDialog = new ProgressDialog(this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage(myUI.INSTALLING_DB); progressDialog.setCancelable(false); new InstallDBData().execute(""); } 

Код для асинхронного потока:

 private class InstallDBData extends AsyncTask<String, Integer, Integer> { @Override protected Integer doInBackground(String... arg0) { progressDialog.setProgress(0); dbWord.installData(0, getApplicationContext()); progressDialog.setProgress(20); dbWord.installData(1, getApplicationContext()); progressDialog.setProgress(40); dbWord.installData(2, getApplicationContext()); progressDialog.setProgress(60); dbWord.installData(3, getApplicationContext()); progressDialog.setProgress(80); dbWord.installData(4, getApplicationContext()); progressDialog.setProgress(100); return 1; } protected void onPreExecute() { progressDialog.show(); } protected void onPostExecute(Integer x) { dbWord.close(); progressDialog.hide(); databaseInstalled = true; clickToStartView.setText(myUI.PRESS_TO_START); clickToStartView.startAnimation(myBlinkAnim); } } 

Это важные части класса WordDBAdapter, который также используется основным видом деятельности:

 public class WordDBAdapter { private DatabaseHelper mDbHelper; private SQLiteDatabase mDb; public WordDBAdapter open() throws android.database.SQLException { mDbHelper = new DatabaseHelper(mCtx); mDb = mDbHelper.getWritableDatabase(); return this; } public void close() { mDbHelper.close(); } ... } 

Я получаю следующие исключения, которые похожи, но имеют другое сообщение:

Первый тип сообщения об ошибке:

 java.lang.RuntimeException: Unable to start activity ComponentInfo{example.flashcards.medical/com.example.flashcards.common.SplashWindow}: android.database.sqlite.SQLiteException: database is locked: BEGIN EXCLUSIVE; at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1830) .... Caused by: android.database.sqlite.SQLiteException: database is locked: BEGIN EXCLUSIVE; at android.database.sqlite.SQLiteDatabase.native_execSQL(Native Method) at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1870) at android.database.sqlite.SQLiteDatabase.beginTransactionWithListener(SQLiteDatabase.java:602) 

Второй тип сообщения об ошибке:

 java.lang.RuntimeException: Unable to start activity ComponentInfo{example.flashcards.medical/com.example.flashcards.common.SplashWindow}: android.database.sqlite.SQLiteException: database is locked at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1768) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1784) .... Caused by: android.database.sqlite.SQLiteException: database is locked at android.database.sqlite.SQLiteDatabase.native_setLocale(Native Method) at android.database.sqlite.SQLiteDatabase.setLocale(SQLiteDatabase.java:1987) at android.database.sqlite.SQLiteDatabase.<init>(SQLiteDatabase.java:1855) at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:820) at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:854) 

Мне бы очень хотелось, чтобы не создавать ContentProvider, потому что я считаю, что его избыток, если доступно более простое решение. Кроме того, только это приложение имеет доступ к базе данных.

Любые предложения о том, как это можно исправить?

Solutions Collecting From Web of "Исключение SQLite: проблема блокировки базы данных"

Сделав некоторое усилие, я сделал это (Мое приложение работало над улучшением до Android 2.3, но получило ошибку блокировки db, когда я использовал его на планшете HoneyComb).
Я использовал семафоры (используя блокировку в критических разделах).

Пример 1

 public class DbExp extends SQLiteOpenHelper{ public static String Lock = "dblock"; private static final String DATABASE_NAME = "db.db"; private static final String TABLE_NAME = "table_name"; public void delete(Context mContext){ synchronized(Lock) { SQLiteDatabase db = getWritableDatabase(); db.delete(TABLE_NAME, null, null); db.close(); } } public void insert(){ synchronized(Lock) { SQLiteDatabase db = getWritableDatabase(); db.insert(TABLE_NAME, ..., ...); db.close(); } } } 

Пример 2

 public class DB { public static String Lock = "dblock"; private static final String DATABASE_NAME = "db.db"; private static final String TABLE_NAME = "table_name"; public void delete(Context mContext){ synchronized(Lock) { SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null); db.delete(TABLE_NAME, null, null); db.close(); } } public void insert(Context mContext){ synchronized(Lock) { SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null); db.insert(TABLE_NAME, ..., ...); db.close(); } } } 

Надеюсь, это поможет любому в будущем 🙂

Если вы используете Фрагменты и это происходит с изменениями ориентации, это потому, что у вас есть два экземпляра одного и того же фрагмента, и оба они имеют свой собственный экземпляр класса-помощника Db. Чтобы заставить его работать, вам либо нужно уничтожить свой фрагмент при изменении ориентации, либо перестроить его, либо найти способ уничтожить класс помощника Db. Это касается только фрагментов с проблемами ориентации. Я должен был сделать много проблем, чтобы понять это, так что, надеюсь, кто-то найдет это полезным

Для меня это было причиной:

Я забыл завершить транзакцию в моем вызове функции после вставки в db. Поэтому, когда я попытался вставить другую запись из другой активности, я получил исключение блокировки базы данных. Добавление приведенного ниже решения решило мою проблему.

 sqlDB.endTransaction(); 

Я бы предложил вам закрыть свою БД в основной теме и открыть и закрыть ее в методе doInBackground:

  @Override protected Integer doInBackground(String... arg0) { db.open(); try { // your code here } finally { db.close() } return 1; } 

Также вы не должны напрямую вызывать методы пользовательского интерфейса из AsyncTask, поскольку интерфейс не является потокобезопасным. Вместо этого вызовите метод updateProgress из doInBackground и обновите свой прогрессDialog из onProgressUpdate, поскольку onProgressUpdate вызывается из основного потока.

Похоже, это старый вопрос, но, возможно, это поможет кому-то. У меня была такая же проблема, я загружал, вероятно, около десятка таблиц в одной базе данных и регулярно рушился, не всегда, но иногда.

Наконец, и это может быть hackey, я просто создал отдельную базу данных для каждой таблицы. Итак, теперь у меня есть дюжина баз данных, каждая с одной таблицей. Но больше никаких исключений. Код был звуком, создавал, открывал и закрывал правильно, казалось, что где-то возникали столкновения.

Как я уже сказал, вы можете считать его взломанным, но он исправил мою проблему.

децибел

Может быть, это потому, что вы не открыли или не создали базу данных. Попробуйте, если это так.

 mDb = mCtx.openOrCreateDatabase(DatabaseName, SQLiteDatabase.CREATE_IF_NECESSARY, null); 

В классе DatabaseHelper:

 public DatabaseHelper(Context aContext) { mDb = aContext.openOrCreateDatabase(DatabaseName, SQLiteDatabase.CREATE_IF_NECESSARY, null); OpenHelper openHelper = new OpenHelper(aContext, mDb ); mDb = openHelper.getWritableDatabase(); } 

Эти строки кода разрешили мою (ту же) проблему:

(Раньше у меня была транзакция …)

 writableDatabase.endTransaction(); writableDatabase.close(); dbHelper.close();