0

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

4

3 回答 3

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);
于 2013-01-25T16:33:16.643 回答
0

除了(可能)没有阅读setAutoCommit(). 它指出:

这可能不受所有数据库类型的支持。

和。

警告:除非您知道自己在做什么,否则您应该使用 dao.callBatchTasks(Callable) 而不是此方法。

不幸的是,不支持自动提交的数据库类型之一是 Android 下的 SQLite。在 Android 数据库连接中,代码是无操作的。我是故意这样做的,但我会回去验证ORMLite是正确的,并且 Android 不支持它。

如果您想以批处理模式运行许多命令,我建议您改用该dao.callBatchTasks(...)方法。我将更新 javadocs 以更好地解释这一点并进行测试以确保当前的 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;
    }
});
于 2012-06-08T22:58:05.623 回答
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);
    }
}
于 2012-06-11T21:05:51.070 回答