SQLiteException:无法在事务中启动事务(代码1)

时间:2014-08-11 13:56:35

标签: android sqlite sqlexception

我在完成SQLite交易时遇到了问题,我对如何做到这一点感到非常困惑。它从2007年开始看起来像this bug

我正在创建我的employee表(引用另一个表entity),如下所示(为简洁起见):

CREATE TABLE employee (_id INTEGER NOT NULL, PRIMARY KEY ( _id ) , 
FOREIGN KEY (_id) REFERENCES entity(_id)  ON DELETE cascade ON UPDATE cascade DEFERRABLE INITIALLY DEFERRED )

然后我按如下方式运行一个事务(使用SQLiteDatabase对象,我还报告日志中事务的状态):

>> In transaction: false
beginTransaction();
>> In transaction: true
doSomeWrongINSERT();
setTransactionSuccessful();
endTransaction();
>> In transaction: false
SQLiteConstraintException: foreign key constraint failed (code 19)

好的,一切正常。现在,如果我尝试启动新事务或回滚,则都会失败:

>> In transaction: false
beginTransaction();
android.database.sqlite.SQLiteException: cannot start a transaction within a transaction (code 1)

>> In transaction: false
endTransaction();
java.lang.IllegalStateException: Cannot perform this operation because there is no current transaction.

请注意,如果FK是立即而不是延期,所有这一切都不会发生。

3 个答案:

答案 0 :(得分:6)

这似乎是Android中的一个错误。 在SQLiteSession class中,endTransactionUnchecked在执行mTransactionStack之前清除其事务状态(COMMIT),并且不期望数据库的事务可能仍处于活动状态。 (我不认为没有延迟约束就会发生这种情况。)

提交a bug report

答案 1 :(得分:4)

我找到了解决方法:关闭数据库并再次打开它。这将正确更新交易状态。

我仍然向Android报告问题nº74751

答案 2 :(得分:0)

总结答案(感谢:@CL& @ m0skit0),如果endTransaction内有任何异常,则值得恢复交易状态。如果要覆盖applyBatch实施的ContentProvider,可以在中心位置完成此操作:

    @NonNull
    @Override
    public ContentProviderResult[] applyBatch(@NonNull ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {

        SQLiteDatabase db = mDbHelper.getWritableDatabase();    // automatically opens db, if closed.
        try {
            db.beginTransaction();
            ContentProviderResult[] results = super.applyBatch(operations);
            db.setTransactionSuccessful();
            return results;
        } finally {
            try{
                db.endTransaction();
            }catch (Throwable e2){
                //Log.e(LOG_TAG,"Failed to close a db transaction. The only way to recover is to close the db.", e2);
                db.close();
                throw e2;
            }
        }
    }