【问题标题】:Android SQLite Bulk Insert Using Transactions使用事务的 Android SQLite 批量插入
【发布时间】:2015-11-23 07:16:26
【问题描述】:

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

这是我在DatabaseHandler 中对inserting 的方法:

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 方法中运行。

【问题讨论】:

  • 我认为当 db 在几行之前关闭时,您正试图在 db 中执行订单。你不能调用 db.endTransaction();调用后 db.close();尝试将 if/else 放在 db.endTransaction() 之后并告诉我们。希望对你有帮助
  • 抱歉,我的措辞不好。它在一个循环中,所以它被执行了大约 1000 次。非常低效..我知道

标签: android sqlite android-asynctask android-sqlite


【解决方案1】:

您在结束事务之前已经关闭了数据库,而是在结束后关闭它。

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

【讨论】:

  • 我进行了更改,代码正常运行。但是我的插入仍然需要大约 25 秒?这可能是我的平板电脑(Galaxy Tab 3 10.1")的限制吗?当我在 Genymotion 模拟器上运行它时,大约需要 8 秒。
  • @Mark117 你真的应该每行插入一个。并尝试指示您的领域!
  • @Mark117 如果您真的想加快插入速度,ContentValues + db.insert + transactions 不会像准备好的语句那样有帮助。我的回答只解决了你的崩溃问题。请参阅此答案(Section Inser Valuess),因为加速插入已经(令人惊讶地)回答了stackoverflow.com/a/29797229/794088(如果您发现任何有用的信息,请不要忘记投票=)
【解决方案2】:

两个问题

  1. 每个事务只执行一次插入。您需要在同一事务中执行所有插入操作。
  2. 您将在结束事务之前关闭数据库。

您可以创建一个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();
    }
}

【讨论】:

  • 我认为这是我必须要做的。我目前在 for 循环中执行相同的 insertQuestions 方法〜 1000 次。传递列表似乎是解决这个问题的方法。谢谢
【解决方案3】:

我认为您正在逐一使用insertQuestions() 插入问题。所以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;
}

希望对你有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-18
    • 2013-08-15
    相关资源
    最近更新 更多