2

I'm designing out a module in Android that does some processing and then writes to the database using ORMLite transactions. In particular, my background code will be something like:

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;
        }
    }
}

This runnable will then be executed by being submitted to a ThreadPoolExecutor. I want to be able to cancel the background thread if needed and am trying to make sure that if the operation is cancelled, then the transaction will simply fail and do nothing. For example, if I do this:

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

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

Can I be sure that it will be an all or nothing deal with the transaction in ORMLite. That is, there is no cleanup needed and my modelObj will have either both col1 and col2 set or neither set? Do I have to do anything special when catching the InterruptedException in the Runnable to handle the case when a task is cancelled in this way, or can I simply exit?

Faisal
  • 297
  • 2
  • 16

2 Answers2

2

If you call f.cancel(true), all that does is interrupt the Thread which causes wait(), sleep(), and some other methods to throw InterruptedException. It will not cancel the database transaction underway.

If you want, you can check for the interrupted bit in the middle of your IO operations:

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

For more information about what happens when a thread is interrupted see here:

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


Transactions are for when you are updating multiple objects as a single unit or writing to multiple tables. See the documentation about transactions which has an example of updating an Account and an Order inside of a transaction.

Also, you do not need to use a transaction if you are updating multiple fields in the same row. The update statement is considered to be a single unit and the database should ensure that the row gets updated atomically. Only if you are updating multiple different rows either in the same table or in separate tables do you need a transaction.

Community
  • 1
  • 1
Gray
  • 115,027
  • 24
  • 293
  • 354
  • Thanks Gray ... my example was a little careless/rushed, but the focus is on how to cancel the Runnable (respecting db writes in the process). I've updated the example with two separate table edits for correctness. From what you've mentioned, it seems like f.cancel() may not be the way to go as a reliable cancellation of a Runnable op. Wondering if then it's better to create a CancelableRunnable subclass that has a synchronized state var that indicates if it is cancelled and can be checked at diff times and used to exit the normal exec path. – Faisal May 08 '12 at 01:48
  • I'm basically trying to get the equivalent of objective c's [nsoperation cancel] functionality ... if I can even check for cancellation status at strategic times during a Runnable and exit then, that would be fine. – Faisal May 08 '12 at 01:56
  • There is no way to stop a Java thread while running except with `interrupt()` @Faisal. I've updated my answer. – Gray May 08 '12 at 02:07
  • I wasn't referring to stopping the thread itself, but the Runnable being executed on the thread. Basically, something like the SO answer for this thread: http://stackoverflow.com/questions/5844308/removecallbacks-not-stopping-runnable ... I think I'd want that to have synchronized flag for the Runnable kills state (if I'm modifying from some main thread code), but with that I can periodically check if the Runnable has been flagged for killing and just break out of execution there. – Faisal May 08 '12 at 03:16
0

ORMLite will utilize the sqlite transactions under the covers. This is most likely a double phase commit which only allows you to commit a transaction as an entire unit.

In short, you can be assured that col1 and col2 will only be modified as a single atomic unit. Also, it if is interrupted the commit will fail and the changes to col1 and col2 will be rolled back.

Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
John Ericksen
  • 10,995
  • 4
  • 45
  • 75
  • This is wrong in a couple of ways. See my answer. It is not a double locking transaction -- it is just a single transaction which can be committed or rolled back. You don't need a transaction to update multiple columns in the same row. And interrupt does nothing to the transaction calls. It just interrupts `sleep()` or `wait()`. – Gray May 08 '12 at 01:17
  • What I meant to say was "double phase commit" (http://en.wikipedia.org/wiki/Two-phase_commit_protocol) which, across many different database systems, is one way that databases ensure atomic behavior. I agree with you that a transaction is not necessarily needed in this case and, that there is really no way to interrupt the run() method without specifically calling the isInterupted(). – John Ericksen May 08 '12 at 02:45