My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
Transactions  
Transactions with Guice Persist
Updated Oct 16, 2011 by sberlin

Method-level @Transactional

By default, any method marked with @Transactional will have a transaction started before, and committed after it is called.

  @Transactional
  public void myMethod() { ... }

The only restriction is that these methods must be on objects that were created by Guice and they must not be private.

Responding to exceptions

If a transactional method encounters an unchecked exception (any kind of RuntimeException), the transaction will be rolled back. Checked exceptions are ignored and the transaction will be committed anyway.

To change this behavior, you can specify your own exceptions (checked or unchecked) on a per-method basis:

  @Transactional(rollbackOn = IOException.class)
  public void myMethod() throws IOException { ... }

Once you specify a rollbackOn clause, only the given exceptions and their subclasses will be considered for rollback. Everything else will be committed. Note that you can specify any combination of exceptions using array literal syntax:

  @Transactional(rollbackOn = { IOException.class, RuntimeException.class, ... })

It is sometimes necessary to have some general exception types you want to rollback but particular subtypes that are still allowed. This is also possible using the ignore clause:

  @Transactional(rollbackOn = IOException.class, ignore = FileNotFoundException.class)

In the above case, any IOException (and any of its subtypes) except FileNotFoundException will trigger a rollback. In the case of FileNotFoundException, a commit will be performed and the exception propagated to the caller anyway.

Note that you can specify any combination of checked or unchecked exceptions.

Units of Work

A unit of work is roughly the lifespan of an EntityManager (in JPA). It is the session referred to in the session-per-* strategies. We have so far seen how to create a unit of work that spans a single transaction:

...and one that spans an entire HTTP request:

Sometimes you need to define a custom unit-of-work that doesn't fit into either requests or transactions. For example, you may want to do some background work in a timer thread, or some initialization work during startup. Or perhaps you are making a desktop app and have some other idea of a unit of work.

To start and end a unit of work arbitrarily, inject the UnitOfWork interface:

public class MyBackgroundWorker {
  @Inject private UnitOfWork unitOfWork;
 
  public void doSomeWork() {
    unitOfWork.begin();
    try { 
      // Do transactions, queries, etc...
      //...
    } finally {
      unitOfWork.end(); 
    }
  } 
}

You are free to call any @Transactional methods while a unit of work is in progress this way. When end() is called, any existing session is closed and discarded. It is safe to call begin() multiple times--if a unit of work is in progress, nothing happens. Similarly, if one is ended calling end() returns silently. UnitOfWork is threadsafe and can be cached for multiple uses or injected directly into singletons.

Comment by scott.ca...@gmail.com, Jan 27, 2011

Can you configure the default exceptions at the module level? Some JDBC drivers throw all sorts of checked exceptions, it would be critical to have those cause rollback by default instead of forcing boilerplate at every @Transactional tag.

Comment by jovancic...@gmail.com, May 6, 2011

Can unitOfWork be also annotation (like @UnitOfWork?) so we can add it to method doSomeWork, or can you add in @Transaction attribute for that, like is new transaction will be created if method is called from other method that created transaction?

Comment by r...@richardnichols.net, Jun 6, 2011

Personally, I think the @Transactional default behavior is not very sensible. A more sensible default would be to rollback on any type of exception. If you want to do different then you can override.

To throw an exception but to continue with the transaction.commit() seems like a way of return something from a method, via an exception. Wouldn't it be better to return it from the method as part of its return type?

Comment by rugo...@gmail.com, Jul 23, 2011

Do you support attributes like "RequiresNew?" on the Transactional annotation? So the method that uses it is kicked off in a different thread and transaction and the caller of the method continues its work in the original ones?

Comment by fernando...@gmail.com, Dec 27, 2011

+1 for rugo...@gmail.com. Hope next release will come with this option.

Comment by michael....@gmail.com, Apr 24, 2012

This says that the method annotated with @Transactional "must not be private".

It should also state that neither does it work with package (no modifier) - the method must be marked public or protected or no transaction will be opened.

Comment by caarlos0, May 3, 2012

I have an app managed by maven with two modules: one for persistence, and another for the webapp itself (gwt).

My tests in persistence module works like a charm, but, in webapp, when I execute the same method multiple times I got a java.lang.IllegalStateException?: Attempting to execute an operation on a closed EntityManager?..

I use guice-persist to inject the entity manager into my DAOs, and all my DAO methods have the @Transactional annotation.

In my webapp, I put a: public class ScuvServletModule? extends ServletModule {

@Override protected void configureServlets() {
super.configureServlets(); install(MyPersistenceAPI.getModule()); // return my module and install it filter("/").through(PersistFilter?.class); /// another bindings...
}

}

If I remove the PersistFilter?, it wotks, but randomly throws a Transaction Closed exception or something like that.

Any help?


Sign in to add a comment
Powered by Google Project Hosting