Reputation: 9065
I have a hibernate session that retrieved from sessionFactory.openSession()
, And some complex computing to the Entities
and also I want to persistent(UPDATE, INSERT, DELETE
) some Entities
during the computing.
Here is a case:
Consider that I have a ProductEntity
that represents a product, and an OrderEntity
which represents the order record of the product, and a UserEntity
which represents the user who book the order of the product.
I know I can process an booking operation this way:
public void addOrder(UserEntity userEntity, ProductEntity productEntity, int quantity){
session = sf.openSession();
Transaction tx = session.beginTransaction();
//do some compution and generate the orderEntity and persistent it to the db.
try{
tx.commit();
}catch(Exception e){
tx.rollback();
}finnaly{
session.close();
}
}
Now I have to add more action to the procedure, such as (Maybe) making a NotifyEntity
and stored in db which represents the notify records to the Merchant who owns the product. this notify
record could be generated by the orderEntity
and has nothing to do with the productEntity
or UserEntity
, in fact, I want this notifyMerchantByOrderEntity
method separated-out of the addOrder
procedure so that I can reuse this method and clarify the code( I really don't want to mess-up with a bulk of codes in the same method, in fact if the checking logic is complex enough, the code of the addOrder
method could be very-very loooong).
Anyhow, I want to :
Something like this:
public void addOrder(UserEntity userEntity, ProductEntity productEntity, int quantity){
Session session = sf.openSession();
session.beginTransaction();
invokeOtherMethod(); //invoking other method which also contains some db operation.
try{
tx.commit()
}catch(Exception e){
tx.rollback(); //this should rollback the operation in invokeOtherMethod() too.
}finally{
session.close();
}
}
Upvotes: 3
Views: 3146
Reputation: 153770
You should switch to using Spring TransactionManager as it allows you to group multiple DAO calls into the same database transaction.
If you don't want to use Spring, you can still implement the transaction management logic using a Service Layer method interceptor (maybe a Dynamic Proxy or Javassist) that employs a ThreadLocal storage to bind the current Thread to the same Hibernate Session
When you enter the transaction boundary you open the transaction and when you leave the transaction boundary, you commit the transaction if there is no exception being thrown or roll it back if you caught any Exception:
private SessionFactory sf;
private final ThreadLocal<Session> sessionStorage =
new ThreadLocal<Session>();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Session session = sessionStorage.get();
if(session == null) {
session = sf.openSession();
}
Transaction tx = session.beginTransaction();
try{
return method.invoke(target, args);
tx.commit();
}catch(Exception e){
tx.rollback();
throw new ServiceException(e);
}finally{
session.close();
sessionStorage.remove();
}
}
Now you'll have to weave this interceptor to all Service method calls.
Upvotes: 1
Reputation: 9065
I found a alternative way to do this which pass the session
to the method that will be invoked. And test demos show I can also rollback the db operations in the invoked method when Exception occurs, Although the answer @Vlad given may worth a trial. I post my way of doing this here hoping it may inspire guys meet with similar issue.
public OrderEntity addOrder(UserEntity userEntity, ProductEntity, int quantity){
Session session = sf.openSession();
try{
Transaction tx = session.beginTransaction();
OrderEntity orderEntity = new OrderEntity(userEntity, productEntity, quantity);
session.save(orderEntity);
notifyMerchant(orderEntity, session); //here we will invoke another method with session together.
tx.commit();
return orderEntity;
}catch(Exception e){
e.printStack();
tx.rollback(); // if Exception occurs all the operations making to the db will be rollback, as well as those operations in method notifyMerchant();
return null;
}finally{
session.close();
}
}
private void notifyMerchant(OrderEntity orderEntity, Session session){
NotifyEntity notifyEntity = new NotifyEntity(orderEntity);
notifyEntity.notifyMerchant();
session.save(notifyEntity); // this will save the notifyEntity to db as a sort of log stuff;
}
@Vlad may give a better way of doing this, currently the above implement is the way with less change of my project.
Upvotes: 1