我按照How to use Dao.setAutoCommit()?中的说明尝试禁用自动提交,因此我可以批量运行提交。
每当我真的尝试运行代码时,我的程序会跟踪我在DAO上调用create和类似操作的次数,当它大于批量大小时,会调用dao.commit()。 ..然后我会得到这个错误(SaveJsonParser是带代码的类的名称):
06-08 17:18:50.866:E / AndroidRuntime(30993):java.lang.Runtime
Exception: An error occured while executing doInBackground()
06-08 17:18:50.866: E/AndroidRuntime(30993): at android.os.AsyncTask$3.done(AsyncTask.java:200)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.util.concurrent.FutureTask.run(FutureTask.java:138)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.lang.Thread.run(Thread.java:1019)
06-08 17:18:50.866: E/AndroidRuntime(30993): Caused by: java.lang.IllegalStateException: no transaction pending
06-08 17:18:50.866: E/AndroidRuntime(30993): at android.database.sqlite.SQLiteDatabase.setTransactionSuccessful(SQLiteDatabase.java:673)
06-08 17:18:50.866: E/AndroidRuntime(30993): at com.j256.ormlite.android.AndroidDatabaseConnection.commit(AndroidDatabaseConnection.java:77)
06-08 17:18:50.866: E/AndroidRuntime(30993): at com.j256.ormlite.dao.BaseDaoImpl.commit(BaseDaoImpl.java:811)
06-08 17:18:50.866: E/AndroidRuntime(30993): at com.visitsanantonio.save.data.SaveJsonParser.commitCategories(SaveJsonParser.java:412)
06-08 17:18:50.866: E/AndroidRuntime(30993): at com.visitsanantonio.save.data.SaveJsonParser.parseDeal(SaveJsonParser.java:278)
06-08 17:18:50.866: E/AndroidRuntime(30993): at com.visitsanantonio.save.data.SaveJsonParser.parseNewUpdatedDeals(SaveJsonParser.java:233)
06-08 17:18:50.866: E/AndroidRuntime(30993): at com.visitsanantonio.save.data.SaveJsonParser$JsonParsingTask.doInBackground(SaveJsonParser.java:479)
06-08 17:18:50.866: E/AndroidRuntime(30993): at com.visitsanantonio.save.data.SaveJsonParser$JsonParsingTask.doInBackground(SaveJsonParser.java:1)
06-08 17:18:50.866: E/AndroidRuntime(30993): at android.os.AsyncTask$2.call(AsyncTask.java:185)
06-08 17:18:50.866: E/AndroidRuntime(30993): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
06-08 17:18:50.866: E/AndroidRuntime(30993): ... 4 more
经过一些实验,看起来我的代码实际上并没有禁用autoCommit,正如后台线程中运行的已清理,截断的示例所示:
conn = dao.startThreadConnection();
Log.e(TAG, "dao auto commit: " + dao.isAutoCommit(conn));
dao.setAutoCommit(conn, false);
Log.e(TAG, "dao auto commit: " + dao.isAutoCommit(conn));
检查日志,我看到两个日志行都显示为“true”。我实际上并没有改变它是否自动提交。我做错了什么?
答案 0 :(得分:2)
基于格雷的解决方案和方法......
accountDao.callBatchTasks(connectionSource,
new Callable<Void>() {
public Void call() throws SQLException {
// insert a number of accounts at once
for (Account account : accountsToInsert) {
// update our account object
accountDao.create(account);
}
return null;
}
});
我写了一个静态方法作为通用版本:
public static <T, K> void batchCommit(final List<T> objectsToCommit, final Dao<T, K> dao) throws Exception {
dao.callBatchTasks(new Callable<Void>() {
@Override
public Void call() throws Exception {
for (T obj : objectsToCommit) {
dao.create(obj);
}
return null;
}
});
}
可以像这样调用:
'DaoUtil'.batchCommit(accountsToinsert, accountDao);
答案 1 :(得分:0)
除了(可能)没有阅读Javadocs on setAutoCommit()
之外,你没有做任何错误。它声明:
所有数据库类型可能都不支持。
和
警告:除非您知道自己在做什么,否则有可能使用dao.callBatchTasks(Callable)代替此方法。
不幸的是,其中一种不支持自动提交的数据库类型是Android下的SQLite。在Android数据库连接中,代码是无操作。我是故意这样做的,但我会回去验证ORMLite是否正确并且Android不支持它。
如果您想以批处理模式运行多个命令,我建议您改用dao.callBatchTasks(...)
method。我将更新javadoc以更好地解释这一点并进行测试以确保当前的ORMlite代码在Android下不使用自动提交是正确的。类似的东西:
accountDao.callBatchTasks(connectionSource,
new Callable<Void>() {
public Void call() throws SQLException {
// insert a number of accounts at once
for (Account account : accountsToInsert) {
// update our account object
accountDao.create(account);
}
return null;
}
});
答案 2 :(得分:0)
这是我最终提出的批量处理数据库请求的清理版本。这种方法不会崩溃,并且希望它实际上可以批量处理数据库请求(而不是单独提交每个对象或者尝试为单个提交累积大量事务)。
final static Integer BATCH_SIZE = 100;
int index = 0;
public int processInBatch(final Collection objectsToProcess)
throws java.sql.SQLException {
final int len = objectsToProcess.length();
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() throws Exception {
int endIndex = index + BATCH_SIZE;
if (endIndex > len) {
endIndex = len;
}
for (; index < endIndex; index++) {
MyObject o = objectsToProcess.get(index);
try {
dao.createOrUpdate(o);
} catch (java.sql.SQLException se) {
Log.e(TAG, "error while attempting to add or update myobject with id of " + o.getId(), se);
}
}
return null;
}
};
ConnectionSource source = databaseHelper.getConnectionSource();
while (index < len) {
TransactionManager.callInTransaction(source, callable);
}
}