Kohei Nozaki's blog 

Testing guice-persist nested @Transactional behavior


Posted on Wednesday Dec 23, 2015 at 01:41PM in Technology


There is no mention of nested use of @Transactional in the Transactions page of official Guice Wiki so I’ve done some testing about how transactions will be treated in nested use.

As it turns out, Guice seems ignore any of nested @Transactional and any of its rollbackOn attributes. It’s all up to the parent invoker.

For testing, I created two classes as following UML diagram:

b03b90cb 0b01 4601 9dac 755d79f2347e

EnclosingService holds a reference to EnclosedService and invokes a method of it from every method of EnclosingService. Each name of methods state that what exception will be thrown from the method. For example, EnclosedService#runtimeException() throws RuntimeException while EnclosedService#noException() won’t throw any of Exception. EnclosedService#ioExceptionWithRollbackOn() throws IOException and annotated as @Transactional(rollbackOn = IOException.class). And names of methods of EnclosingService states same but the part of after _ means that what method of EnclosedService will be invoked.

All of methods in both services save a Entity with em.persist() then invoke em.flush() so that every changes will be flushed immediately. i.e. EnclosingService#noException_noException() saves two entities that one in the method itself and another one in the enclosing invocation of EnclosedService#noException().

Then I created a test case which has 16 test methods that covers all of methods defined in EnclosingService and found that any of @Transactional annotation or rollbackOn attribute in EnclosedService are being ignored. I summarized the result in a table:

0f595e00 fad6 4df1 b0d6 442024eca778

I can see all of operations are atomic and any Exception thrown in methods of EnclosedService doesn’t affect the result if the transaction will be committed or rolled back. When Guice detects that it’s a RuntimeException or a checked exception that defined as rollbackOn in the first method which annotated as @Transactional then rollback happen.

All resources that used in this test can be obtained from my GitHub repository. It used in-memory database of Apache Derby so that everyone can execute the testcase without any annoying preparation. Also EclipseLink 2.5.1, Guice 3.0 and log4jdbc are used so that I can see how transaction is going such as commit / rollback.