Android: SQLite "database locked" onUpgrade 后第一次 getWritableDatabase() 执行尝试时出现异常

Android: SQLite "database locked" exception on first getWritableDatabase() execution attempt after onUpgrade

在我的应用程序中,我有一个 SQLiteHelper class,如下所示:

class SQLiteHelper extends SQLiteOpenHelper
{
    private static WeakReference<Context> _context; 
    private static final String DATABASE_NAME = "database_name";
    private static final int DATABASE_VERSION = 2;

    SQLiteHelper(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        _context = new WeakReference<>(context);
    }

    @Override
    public void onCreate(SQLiteDatabase database)
    {
        InputStream is = _context.get().getResources().openRawResource(R.raw.my_database_dump);
        generateSqliteStringBuilder(database, is);
    }

    @Override
    public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion)
    {
        InputStream is = null;

        if (oldVersion < 2)
        {
            is = _context.get().getResources().openRawResource(R.raw.my_database_dump_1_to_2);
        }

        if (is!=null) generateSqliteStringBuilder(database, is);
    }

    private void generateSqliteStringBuilder(SQLiteDatabase database, InputStream is)
    {
        StringBuilder out = new StringBuilder();
        InputStreamReader in = new InputStreamReader(is);
        BufferedReader reader = new BufferedReader(in);

        String line;
        try {
            while ((line = reader.readLine())!=null) out.append(line.replaceAll(";$", ";;"));
            is.close();
            reader.close();
            executeSQLScript(out, database);
        } catch (IOException e) {
            ExceptionHandler.logException(e);
        }
    }

    private void executeSQLScript(StringBuilder out, SQLiteDatabase database)
    {
        try
        {
            String replacedOut = out.toString().trim();
            String[] sql = replacedOut.split(";;");
            for (String statement : sql) {
                if (!statement.contains("android_metadata")) {
                    database.execSQL(statement + ";");
                }
            }
        } catch (Exception e) {
            ExceptionHandler.logException(e);
        }
    }

    public String replace(CharSequence target, CharSequence replacement)
    {
        return Pattern.compile(target.toString(), Pattern.LITERAL)
                .matcher(target).replaceAll(Matcher.quoteReplacement(replacement.toString()));
    }
}

然后我有一个实体 - 它将使用 SQLite 存储库 - 如下所示:

... ENTITY GETTERS AND SETTERS

public static MyEntity1 getMyEntity1(int id, int idLanguage)
{
    MyEntity1 entity1 = null;
    Entity1Repository datasource = new Entity1Repository();

    String strResult = datasource.open();
    if (strResult.equals(Enum.Result.OK)){
        entity1 = datasource.getEntity1(id, idLanguage);
    }
    datasource.close();

    return entity1;
}

... MORE REPOSITORY METHODS

我终于有了一个 Entity1 存储库,如下所示:

public class Entity1Repository {

    private SQLiteDatabase database;

    public Entity1Repository() {

        dbHelper = new SQLiteHelper(AppSettings.getContext());
    }

    public String open() {

        String strResult = Enum.Result.OK;

        try {
            database = dbHelper.getWritableDatabase();
        } catch (Exception e) {
            strResult = Enum.Result.KO;
            ExceptionHandler.logException(e);
        }

        return strResult;
    }

    public void close() {
        dbHelper.close();
    }

    public Entity1 getEntity1(int id, int idLanguage) {

        Entity1 entity1 = null;
        String strWhere = SQLiteHelper.TABLE_ENTITY1_COLUMN_ID + "= ? AND " +
                SQLiteHelper.TABLE_ENTITY1_COLUMN_IDLANGUAGE + "= ?";

        Cursor cursor = database.query(SQLiteHelper.TABLE_ENTITY1,
                allColumns, strWhere, new String[] {String.valueOf(id), String.valueOf(idLanguage)}, null, null, null, null);

        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            entity1 = cursorToEntity1(cursor);
            cursor.moveToNext();
        }
        cursor.close();
        return entity1;
    }

    ...
}

SQLite 1_to_2 转储文件:

BEGIN TRANSACTION;

...
INSERTS
...

COMMIT;

直到现在我必须更新我的数据库版本,一切都运行良好。我已经将 DATABASE_VERSION 从 1 增加到 2,并且在调用 onUpgrade 之后,当下一个 "database = dbHelper.getWritableDatabase()" 即将执行时,抛出 "database locked" 异常。

经过几个小时的调试,我完全卡住了。

onCreate()onUpgrade()已经在事务中执行,sqlite并不真正支持嵌套事务。

从您的 SQL 脚本中删除 BEGIN TRANSACTIONCOMMIT