You can use a template method pattern and an interface callback for the template method's implementation.
A quick and short example of such a template method pattern could look like this:
public class TransactionTemplate {
public <T> T execute(Callable<T> doInTransaction) throws Exception {
EntityManager em = EntityManagerFactory.get();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
try {
T result = doInTransaction.call();
transaction.commit();
return result;
} catch(/* Some exception that causes a rollback */ e) {
transaction.rollback();
throw e;
} finally {
em.close();
}
}
}
In your code you can then use it this way
private updateDB() {
TransactionTemplate transaction = ... // get it somehow;
transaction.execute(new Callable<Void>(){
// will be executed in a transaction
public Void call() throws Exception {
//do some DB stuff
}
});
}
Note: This is exactly the same pattern that spring's TransactionTemplate
uses. So if you can use spring you will get it for free.
Edit according to user3111525 comment
There is no reference to it passed. If for example the operation is to persist(), how can it do it? ... Guess there is a need to use ThreadLocal`?
There are several ways you can make the EntityManager
reference available to the Callable
- Use a
ThreadLocal
as user3111525 proposed in the comment
- Instead of using a standard
Callable<T>
introduce an own interface, e.g. EMAwareCallable.call(EntityManager)
.
- If the
Callable
is a anonymous class provide it by a final variable of the enclosing class.
- Create a class that implements
Callable
and add a constructor to pass the reference to it.
Each way has it's pros and cons in implementation effort, testability, extensibility (standard java interface or not), and so on. It's up to you to make a choice.