执行一些SQLite操作时“失败21(内存不足)”

时间:2011-08-15 20:28:05

标签: android sqlite

我的应用程序将其本地SQLite数据库与Amazon服务器上存在的外部数据库同步。有时,同步失败并产生此logcat输出:

08-15 19:58:38.149: ERROR/Database(343): Failure 21 (out of memory) on 0x0 when preparing 'drop table if exists keymap2'.
08-15 19:58:38.149: ERROR/KeymapDbHelper(343): Error occurred while syncing DB
08-15 19:58:38.149: ERROR/KeymapDbHelper(343): android.database.sqlite.SQLiteException: unknown error: drop table if exists keymap2
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at android.database.sqlite.SQLiteDatabase.native_execSQL(Native Method)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1610)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.db.KeymapDbHelper.syncToTempTable(KeymapDbHelper.java:114)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.db.KeymapDbHelper.syncDb(KeymapDbHelper.java:84)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.MainMenuActivity$DbSyncTask.doInBackground(MainMenuActivity.java:221)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.MainMenuActivity$DbSyncTask.doInBackground(MainMenuActivity.java:1)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.lang.Thread.run(Thread.java:1096)

当发生这种情况时,我的应用程序会通知我同步失败,所以我要求它再次尝试同步,大约有50-75%的时间可以同步。

以下是执行同步的代码:

@SuppressWarnings("unchecked")
private void syncToTempTable(SQLiteDatabase db, String table)
        throws DatabaseMismatchException {
    String awsSql = "select * from " + keymapDb;
    SelectRequest select = new SelectRequest(awsSql);
    SelectResult result;

    Log.d(TAG, "Making request: " + awsSql);
    result = simpleDB.select(select); // Could throw AmazonClientException

    List<Item> items = result.getItems();

    db.execSQL("drop table if exists " + table);
    String tempSql = "create table " + table + " (" +
            C_KEY + " text primary key, " +
            C_NAME + " text)";
    db.execSQL(tempSql);
    Log.d(TAG, "SQL executed: " + tempSql);

    ContentValues cv = new ContentValues();
    for (Item i : items) {
        cv.clear();
        String key = i.getName();
        cv.put(C_KEY, key);

        List<Attribute> attributes = i.getAttributes();
        assert attributes.size() <= 1;
        for (Attribute a : attributes) {
            String name = a.getName();
            String value = a.getValue();

            if ((key.equals(R_INFO) && !name.equals(C_REVISION)) || 
                    (!key.equals(R_INFO) && !name.equals(C_NAME)))
                throw new DatabaseMismatchException("DB not synced because " +
                        "column " + name + " was unexpected");

            cv.put(C_NAME, value);
        }

        db.insert(table, null, cv);
    }
}

第114行是db.execSQL("drop table if exists " + table);

该行的目的是删除临时表,如果由于某种原因,应用程序已事先崩溃并阻止表被删除,因为它通常会这样做。我注意到,如果该表单独存在,应用程序将在尝试创建具有相同名称的新表时崩溃。

为什么我的应用程序在这里耗尽了内存,我该怎么做才能解决它?

编辑:好的,它确实会在应用程序与外部数据库同步时发生。

1 个答案:

答案 0 :(得分:5)

事实证明,在我的应用程序进行此方法调用之前,此错误是编程错误的结果。在我致电syncToTempTable()之前,我打开了数据库:

SQLiteDatabase db = dbHelper.getWritableDatabase();

在此之后,我想检查本地数据库的修订号。我以前做的方法也打开了数据库(基本上我打开了我的数据库两次),然后关闭它(这可能会关闭所有打开的数据库流)。因此,我没有意识到我正在给syncToTempTable()一个封闭的数据库。

现在问题解决了。