【问题标题】:Cancelling ORMLite Write in Background Thread Safely在后台线程中安全地取消 ORMLite 写入
【发布时间】:2012-05-07 23:24:00
【问题描述】:

我正在 Android 中设计一个模块,该模块进行一些处理,然后使用 ORMLite 事务写入数据库。特别是,我的背景代码将类似于:

public class BackgroundOperation implements Runnable {
        @Override
    public void run() {
        //Do some stuff

        //Write to the database in a transaction
        try {

            ORMHelper h = ORMHelper.getDefaultOrmHelper();
            final MyModel modelObj = h.myModelDao.queryForId(someId);
            TransactionManager.callInTransaction(
                h.getConnectionSource(),
                new Callable<Void>() {
                    public Void call() throws Exception {
                        modelObj.col1 = 10;
                        modelObj.col2 = "hello";
                        h.myModel2Dao.update(modelObj);
                        h.myModel2Dao.create(new MyModel2("a", "b"));
                        return null;
                    }
                }
            );
        }
        catch (Exception e) {
            return null;
        }
    }
}

这个runnable 然后将通过提交给ThreadPoolExecutor 来执行。如果需要,我希望能够取消后台线程,并试图确保如果操作被取消,那么事务将简单地失败并且什么都不做。例如,如果我这样做:

Future f = myThreadPoolExecutor.submit(new BackgroundOperation());

//Some time later
f.cancel(true);

我可以确定这将是全有或全无处理 ORMLite 中的事务。也就是说,不需要清理,我的 modelObj 将同时设置 col1 和 col2 或都不设置?在 Runnable 中捕获 InterruptedException 时是否需要做一些特殊的事情来处理以这种方式取消任务的情况,或者我可以简单地退出吗?

【问题讨论】:

    标签: android multithreading sqlite ormlite


    【解决方案1】:

    如果您调用f.cancel(true),所做的只是中断Thread,从而导致wait()sleep() 和其他一些方法抛出InterruptedException。它不会取消正在进行的数据库事务。

    如果需要,您可以在 IO 操作中间检查中断位:

    h.myModel2Dao.update(modelObj);
    if (Thread.currentThread().isInterrupted()) {
       throw new RuntimeException("Thread was interrupted");
    }
    h.myModel2Dao.create(new MyModel2("a", "b"));
    

    有关线程中断时发生的情况的更多信息,请参见此处:

    What does java.lang.Thread.interrupt() do?


    事务用于将多个对象作为一个单元更新或写入多个表时。请参阅documentation about transactions,其中有一个在事务内部更新AccountOrder 的示例。

    此外,如果您要更新同一行中的多个字段,则无需使用事务。更新语句被认为是一个单一的单元,数据库应确保该行自动更新。只有在同一个表或不同表中更新多个不同行时,才需要事务。

    【讨论】:

    • 谢谢 Gray ...我的例子有点粗心/匆忙,但重点是如何取消 Runnable(尊重进程中的 db 写入)。为了正确起见,我使用两个单独的表格编辑更新了示例。从您提到的内容来看,似乎 f.cancel() 可能不是可靠取消 Runnable 操作的方法。想知道是否最好创建一个具有同步状态 var 的 CancelableRunnable 子类,该状态变量指示它是否已取消,并且可以在不同时间检查并用于退出正常的 exec 路径。
    • 我基本上是在尝试获得与目标 c 的 [nsoperation cancel] 功能等效的功能......如果我什至可以在 Runnable 期间的战略时间检查取消状态并退出,那很好.
    • 除了interrupt()@Faisal 之外,没有办法在运行时停止 Java 线程。我已经更新了我的答案。
    • 我不是指停止线程本身,而是在线程上执行 Runnable。基本上,类似于此线程的 SO 答案:stackoverflow.com/questions/5844308/… ...我想我希望它具有 Runnable 杀死状态的同步标志(如果我正在从一些主线程代码进行修改),但是我可以定期检查 Runnable 是否已被标记为杀死并在那里中断执行。
    【解决方案2】:

    ORMLite 将在幕后利用 sqlite 事务。这很可能是双阶段提交,它只允许您将事务作为一个整体提交。

    简而言之,您可以放心 col1 和 col2 只会被修改为单个原子单元。此外,如果被中断,提交将失败并且对 col1 和 col2 的更改将被回滚。

    【讨论】:

    • 这在几个方面是错误的。看我的回答。它不是双重锁定事务——它只是一个可以提交或回滚的事务。您不需要事务来更新同一行中的多个列。并且中断对事务调用没有任何作用。它只是中断sleep()wait()
    • 我的意思是“双阶段提交”(en.wikipedia.org/wiki/Two-phase_commit_protocol),在许多不同的数据库系统中,它是数据库确保原子行为的一种方式。我同意你的观点,在这种情况下不一定需要事务,并且如果不专门调用 isInterupted(),就没有办法中断 run() 方法。
    猜你喜欢
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多