SQLiteexception:数据库已锁定问题

我在Android应用程序中遇到了SQLite数据库的问题。 它似乎经常发生,我无法重现它,但这是Android Market提供的报告。

基本上我首先有一个启animation面活动,首先检查所有需要的数据是否在数据库中。 如果没有,它将在异步线程中安装数据并关闭数据库连接。

然后,只有这样才能启动主要活动,这也会打开并读取/写入数据库。

此代码从启动屏幕活动的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 { @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(); } ... } 

我得到以下exception,这些exception相似但有不同的消息:

第一种错误信息:

 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.(SQLiteDatabase.java:1855) at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:820) at android.database.sqlite.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:854) 

我真的不想创建一个ContentProvider,因为我认为如果有一个更简单的解决方案,那就太过分了。 此外,只有此应用程序才能访问数据库。

关于如何解决这个问题的任何建议?

做了一些努力后,我做了它(我的应用程序正在完善直到android 2.3,但我曾经在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(); } } } 

希望这将有助于未来的任何人:)

如果您使用Fragments并且它发生了方向更改,那么因为您有两个相同Fragment的实例,并且它们都有自己的某种Db帮助程序类的实例。 为了使其工作,您必须在方向更改时销毁片段并重建它,或者find销毁Db助手类的方法。 这仅适用于具有方向问题的片段。 我不得不做很多故障排除才能搞清楚,所以希望有人觉得这很有帮助

这是我的理由:

插入到db。之后,我忘了在函数调用中结束事务。当我尝试从另一个活动插入另一个记录时,我得到了数据库锁定exception。 添加以下语句解决了我的问题。

 sqlDB.endTransaction(); 

我建议你在主线程中关闭你的数据库,并在你的doInBackground方法中打开并关闭它:

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

此外,您不应该直接从AsyncTask调用UI方法,因为UI不是线程安全的。 而是从doInBackground调用方法updateProgress并从onProgressUpdate更新progressDialog,因为onProgressUpdate是从主线程调用的。

看起来这是一个较老的问题,但也许这会对某人有所帮助。 我遇到了同样的问题,我在一个数据库中加载了大约十几个表,并且经常会崩溃,但并不总是,但有时候会崩溃。

最后,这可能是hackey,我刚为每个表创建了一个单独的数据库。 所以现在我有十几个数据库,每个数据库都有一个表。 但是,没有例外。 代码是声音,正在创建,正确打开和关闭,似乎只是在某处发生碰撞。

就像我说你可能会认为它是hackey,但它解决了我的问题。

D b

可能是因为你没有正确打开或创建数据库。 如果是这样的话,试一试。

 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();