使用事务的 Android SQLite 批量插入
Posted
技术标签:
【中文标题】使用事务的 Android SQLite 批量插入【英文标题】:Android SQLite Bulk Insert Using Transactions 【发布时间】: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 次。非常低效..我知道 【参考方案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),因为加速插入已经(令人惊讶地)回答了***.com/a/29797229/794088(如果您发现任何有用的信息,请不要忘记投票=)【参考方案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;
希望对你有帮助!
【讨论】:
以上是关于使用事务的 Android SQLite 批量插入的主要内容,如果未能解决你的问题,请参考以下文章