Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does rollback terminates the session?

I'm getting the following exception for below scenario:

java.lang.IllegalStateException: Session/EntityManager is closed

I'm creating a transaction in which I'm saving objects using session.save(); I have not committed the transaction but, i'm using flush to send data to database. can anybody clear my concept for rollback? how does it work? using flush and not commit.

Can anybody explain me below code of mine, I have just started learning hibernate.

Transaction tr1 = session.beginTransaction();
     session.save(c1);
     session.save(c2);
     c3.setCustName("Robby");
     session.save(c3);
     session.flush();
     tr1.rollback();

     session.save(c4);//Here its throwing above mentioned exception.
     session.save(c5);
     tr1.commit();  

Thanks in advance.. !

like image 366
konark Avatar asked Aug 23 '26 04:08

konark


1 Answers

In your use case, it looks like what you're trying to accomplish is to execute two transactions with the same session. The easiest way to do this would be like this

Session session = // you acquire a session from somewhere
try {
  // First trx
  session.getTransaction().begin();
  session.save( c1 );
  session.save( c2 );
  c3.setCustName( "Robby" ); 
  session.save( c3 );
  // at this point nothing has been sent to the database
  // if you want to send it to the db and start a new trx
  // you don't need to use flush, just commit it.
  session.getTransaction().commit();

  // Start a new trx
  session.getTransaction().begin();
  session.save( c4 );
  session.save( c5 );
  session.getTransaction().commit();
}
catch ( Exception e ) {
  if ( session.getTransaction().isActive() ) {
    session.getTransaction().rollback();
  }
  throw e;
}
finally {
  if ( session != null && session.isOpen() ) {
    session.close();
  }
}

The main problem with this is that there is the potential that the first transaction succeeds without an issue but your second transaction fails, which depending on your use case might imply inconsistent database state when you want it all to be committed or nothing at all.

A better implementation would be this:

Session session = // you acquire a session from somewhere
try {
  // First trx
  session.getTransaction().begin();
  session.save( c1 );
  session.save( c2 );
  c3.setCustName( "Robby" ); 
  session.save( c3 );

  session.save( c4 );
  session.save( c5 );
  session.getTransaction().commit();
}
catch ( Exception e ) {
  if ( session.getTransaction().isActive() ) {
    session.getTransaction().rollback();
  }
  throw e;
}
finally {
  if ( session != null && session.isOpen() ) {
    session.close();
  }
}

Having said that, understand that when a Transaction has been marked for rollback either by you calling Transaction#rollback() or some internal exception handling code having done the same, that cannot be undone.

Furthermore, it generally implies the state in the session's cache is for all intents and purposes undefined. If you look at most examples of how rollback gets handled, you'll often see that the only option is to close that session and attempt to start with a brand new session, not just a transaction.

So the exception you get is to prevent users from essentially using a Session or EntityManager where the persistence context state is likely undefined due to an active transaction having been marked for rollback.

like image 188
Naros Avatar answered Aug 25 '26 07:08

Naros