Reputation: 6774
I can not get SQLite to support my begin/end transaction surrounding multiple inserts.
Multiples INSERTs : 2500ms
Using BEGIN and COMMIT : 90ms
Using SELECT and UNION : 40ms
So I looked using begin and commit. What am I doing wrong?
// pseudocode:
ArrayList<Integer> iList = new ArrayList<Integer>();
for (int i = 1; i <= 500; i++) {
iList.add(i);
}
Collections.shuffle(iList);
StringBuilder sb = new StringBuilder("begin transaction;");
for (Integer i: iList) {
sb.append("insert into \"t_order\" (qid) values(");
sb.append(i);
sb.append(");");
}
sb.append(" end transaction;");
// from docs: http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#execSQL(java.lang.String)
// Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
m_db.execSQL(sb.toString());
OK, I did a bit more research and it seems that "Multiple statements separated by semicolons are not supported." What can I do instead to insert and preserve insert order?
Upvotes: 0
Views: 1079
Reputation: 111
This may help :
public void putAll(Context context, LinkedList<HANDLEDOBJECT> objects) {
if (objects.size() < 1 || objects.get(0) == null)
return;
Log.i("Database", "Starting to insert objects to " + getTableName());
List<String> insertCommands = new ArrayList<String>();
int t = 0;
while (t < objects.size()) {
int k = 0;
StringBuilder sb = new StringBuilder();
sb.append("INSERT OR REPLACE INTO ").append(getTableName())
.append("('k', 'v') ");
for (t = t + 0; t < objects.size() && k < 450; t++) {
k++;
if (t % 450 != 0)
sb.append("UNION ");
sb.append("SELECT " + objects.get(t).getId())
.append(" AS k, ")
.append("'"
+ GsonSerializer.getInstance().toJson(
objects.get(t), getHandledObjectType())
+ "'").append(" AS v ");
}
insertCommands.add(sb.toString());
}
for (String insertCommand : insertCommands)
SQLiteClient.getConnetion(context).execSQL(insertCommand);
Log.i("Database", "Successfully inserted " + t + " objects to "
+ getTableName() + "!!!");
System.gc();
}
Upvotes: 0
Reputation: 234847
Use the SQLiteDatabase.beginTransaction()
and SQLiteDatabase.endTransaction()
methods and issue your execSQL call(s) between them. It would also be better style to use a ContentValues
structure instead of doing your own string concatenation:
ContentValues cv = new ContenValues();
m_db.beginTransaction();
try {
for (Integer i: iList) {
cv.put("qid", i);
m_db.insert("t_order", null, cv);
}
m_db.setTransactionSuccessful();
} finally {
m_db.endTransaction();
}
Upvotes: 2
Reputation: 5525
Have a look at the official Android documentation on beginTransaction(). Replace the "..." portion with a loop doing a separate execSQL() call -- there is no need to truncate the statements together in one buffer.
Also, it's often worth it to use a prepared statement. Prepare the statement, begin the transaction, loop for each item binding and executing the statement and finally commit.
Upvotes: 0
Reputation: 180868
Start a transaction, execute each of the INSERTs on separate execSQL()
calls, and then commit the transaction.
You don't need to cluster the INSERTs together in the same execSQL()
call.
Upvotes: 2