setAutoCommit()什么都不做

时间:2012-06-08 22:46:11

标签: android ormlite

我按照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”。我实际上并没有改变它是否自动提交。我做错了什么?

3 个答案:

答案 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);
    }
}