使用事务的Android SQLite批量插入

时间:2015-08-28 15:08:24

标签: android sqlite android-asynctask android-sqlite

我有一个insert语句,我的应用需要大约25秒来插入~1000行。我正在尝试使用Transactions来加快处理时间,但是我无法实现它。

以下是我insertingDatabaseHandler的方法:

public boolean insertQuestions(String gid, String qid, String qname) {
    SQLiteDatabase db = this.getWritableDatabase();
    db.beginTransaction();
    try {
        ContentValues contentValues = new ContentValues();
        contentValues.put(KEY_GID, gid);
        contentValues.put(KEY_QID, qid);
        contentValues.put(KEY_QNAME, qname);

        long result = db.insert(TABLE_QUESTIONS, null, contentValues);
        db.setTransactionSuccessful();
        if (result == -1) {
            db.close();
            return false;
        } else {
            db.close();
            return true;
        }
    } finally {
        db.endTransaction(); //Error is here
    }
}

当我尝试运行上述方法时,我收到以下错误:

08-28 15:50:40.961  20539-20539/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.murrion.navigationdrawer, PID: 20539
java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /storage/emulated/0/testapp3.db
        at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
        at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:522)
        at com.murrion.navigationdrawer.utils.DatabaseHandler.insertQuestions(DatabaseHandler.java:197)

该语句正在我的Activity中的Asynctask方法中运行。

3 个答案:

答案 0 :(得分:4)

您已经在结束交易前关闭了数据库,而是在结束后关闭它。

public boolean insertQuestions(String gid, String qid, String qname) {
    SQLiteDatabase db = this.getWritableDatabase();

    boolean wasSuccess = true;
    try {
        db.beginTransaction();
        ContentValues contentValues = new ContentValues();
        contentValues.put(KEY_GID, gid);
        contentValues.put(KEY_QID, qid);
        contentValues.put(KEY_QNAME, qname);

        long result = db.insert(TABLE_QUESTIONS, null, contentValues);

        if (result == -1) {
            wasSuccess = false;
        } else {
            db.setTransactionSuccessful();
        }
    } finally {
        db.endTransaction(); 
        db.close();
    }
    return wasSuccess;
}

答案 1 :(得分:3)

两个问题

  1. 每个事务只执行一次插入。您需要在同一事务中执行所有插入操作。
  2. 在结束交易之前,您正在关闭数据库。
  3. 您可以创建一个Question类来封装单个问题的数据。在这种情况下,您的方法可能如下所示:

    public boolean insertQuestions(List<Question> questions) {
        SQLiteDatabase db = this.getWritableDatabase();
        db.beginTransaction();
        try {
            ContentValues contentValues = new ContentValues();
            for (Question question : Questions) {
                contentValues.put(KEY_GID, question.gid);
                contentValues.put(KEY_QID, question.qid);
                contentValues.put(KEY_QNAME, question.qname);
                db.insert(TABLE_QUESTIONS, null, contentValues);
            }
            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();
        }
    }
    

答案 2 :(得分:1)

我认为您正在逐个使用beginTransaction()插入问题。因此endTransaction()db.beginTransaction(); for (entry : listOfQuestions) { db.insertQuestions("","",""); } db.setTransactionSuccessful(); db.endTransaction(); 多次调用效率低下。

加速交易需要进行一些更改:

您必须先将所有问题都插入数组,然后使用:

public boolean insertQuestions(String gid, String qid, String qname) {
    SQLiteDatabase db = this.getWritableDatabase();

    boolean wasSuccess = true;
    try {
        db.beginTransaction();
        ContentValues contentValues = new ContentValues();
        contentValues.put(KEY_GID, gid);
        contentValues.put(KEY_QID, qid);
        contentValues.put(KEY_QNAME, qname);

        long result = db.insert(TABLE_QUESTIONS, null, contentValues);

        if (result == -1) {
            wasSuccess = false;
        } else {
            db.setTransactionSuccessful();
        }
    } finally {
        db.endTransaction(); 
        db.close();
    }
    return wasSuccess;
}

您方法中的一些修改。

{{1}}

我希望它有所帮助!