【问题标题】:SQLite exception: Database is locked issueSQLite 异常:数据库被锁定问题
【发布时间】:2015-07-18 20:22:56
【问题描述】:

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

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

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

这段代码是从闪屏活动的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 类的重要部分,主 Activity 也使用该类:

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,因为如果有更简单的解决方案可用,我相信它会矫枉过正。此外,只有这个应用程序可以访问数据库。

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

【问题讨论】:

    标签: android sqlite exception locking


    【解决方案1】:

    在做了一些努力之后,我做到了(我的应用程序在 android 2.3 之前运行完美,但是当我过去在 HoneyComb 平板电脑上运行它时出现 db lock 错误)。
    我确实使用了信号量(在关键部分使用锁)。

    示例 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();
            }
        }
    
    
    }
    

    希望这对将来的任何人都有帮助:)

    【讨论】:

    • 我用这种方式访问​​我的应用程序数据库但在我的情况下不起作用请看看我的问题link is here...
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      这就是我的原因:

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

      sqlDB.endTransaction();
      

      【讨论】:

      • 太棒了。我已经为此苦苦挣扎了好几个小时了……兄弟,你救了我的命。
      【解决方案4】:

      我建议你在主线程中关闭你的数据库并在你的 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。

      【讨论】:

        【解决方案5】:

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

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

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

        分贝

        【讨论】:

        • 请注意,您将无法使用这种方法创建涉及单独数据库中的表的事务。
        • 每个表使用一个数据库会破坏拥有关系数据库的许多目的,例如执行连接或跨多个表进行事务。
        【解决方案6】:

        这可能是因为您没有正确打开或创建数据库。如果是这种情况,请尝试一下。

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

        【讨论】:

        • 这会去哪里?在公共 WordDBAdapter open() 内部?
        • 我已经在我的 DatabaseHelper 类的构造函数中完成了它。我为你编辑我的答案。
        • 你确定需要这个吗?来自有关 SQLiteOpenHelper 的 Android 文档:“您创建了一个实现 onCreate(SQLiteDatabase)、onUpgrade(SQLiteDatabase, int, int) 和可选的 onOpen(SQLiteDatabase) 的子类,如果数据库存在,则此类负责打开数据库,如果存在则创建它没有,并根据需要对其进行升级。事务用于确保数据库始终处于合理状态。我的 DatabaseHelper 类扩展了 SQLiteOpenHelper,因此应该涵盖在需要时打开和创建的内容,对吗?
        • Khawar,我注意到您没有在 DatabaseHelper() 构造函数中调用 super(context, DATABASE_NAME, null, DATABASE_VERSION);
        • @Khawar 不在乎
        【解决方案7】:

        这些代码行解决了我的(同样的)问题:

        (我之前已经打开了我的交易......)

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-07-09
          • 1970-01-01
          • 1970-01-01
          • 2013-12-26
          • 2018-07-13
          • 2011-10-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多