Currently I have this code duplicated in each one of my Controller methods:
Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction();
if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) {
transaction.begin();
}
Is this the correct way or is there a better way of doing this, perhaps in a separate class that I can reference? If so, how? Every time I've tried to put it in a separate class and reference it from other classes, it failed.
edit: I'm trying to use as few external libraries as possible. I wouldn't use Hibernate if Java had an ORM/JPA implementation built into the JDK
Transaction Interface in Hibernate In hibernate framework, we have Transaction interface that defines the unit of work. It maintains abstraction from the transaction implementation (JTA,JDBC). A transaction is associated with Session and instantiated by calling session.
Therefore, you can run multiple transactions on the same Hibernate Session, but there's a catch. Once an exception is thrown you can no longer reuse that Session. My advice is to divide-and-conquer. Just split all items, construct a Command object for each of those and send them to an ExecutorService#invokeAll .
The key to successful Hibernate transaction management is the JPA EntityManager. It's the only JPA component that can start transactions, commit transactions and hook into Hibernate transactions that are already in progress.
In Hibernate, the transaction management is quite standard, just remember any exceptions thrown by Hibernate are FATAL, you have to roll back the transaction and close the current session immediately.
I've run into this myself many times. Ordinarily my first recommendation would be Spring transaction management, however I understand you are trying to limit the number of third party libraries you are using.
Since you're using a static API in your HibernateUtil class, you may find it helpful to consolidate your logic in a method, and putting the 'what you want to do in a transaction' code (which varies controller to controller) in a callback.
First, define an interface to describe each controller's inTransaction behavior:
public interface TransactionCallback {
void doInTransaction();
}
Now, create a static method in your HibernateUtil class to handle beginning, committing, and if necessary rolling back your transactions:
public class HibernateUtil {
public static void inTransaction(TransactionCallback tc) {
Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction();
if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) {
transaction.begin();
try {
tc.doInTransaction();
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
}
}
In your controller, you'd use your new method with an anonymous inner class:
....
HibernateUtil.inTransaction(new TransactionCallback() {
void doInTransaction() {
// do stuff for this controller
}
});
....
This approach should at least take care of the duplication you'd like to eliminate, and there's plenty of room for extending it to handle particular exceptions, etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With