konark
konark

Reputation: 78

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.. !

Upvotes: 3

Views: 2330

Answers (2)

Ninad Gosavi
Ninad Gosavi

Reputation: 138

To check what transaction.rollback() does with your Session and Transaction itself , I wrote following code and tested.

       SessionFactory sf = cf.configure().buildSessionFactory();
       Session session = sf.openSession();

       Transaction tr = ss.beginTransaction();

        System.out.println( "******** before rollback ************");
        System.out.println("is TR active "+tr.isActive());      
        System.out.println("joind with TR "+session.isJoinedToTransaction());
        System.out.println("is open "+session.isOpen());
        System.out.println("is connected "+session.isConnected());

        tr.rollback();

        System.out.println( "******** After rollback ************");
        System.out.println(" is TR active "+tr.isActive());
        System.out.println("joind with TR "+session.isJoinedToTransaction());
        System.out.println("is open "+session.isOpen());
        System.out.println("is connected "+session.isConnected());

In output I got this ,

******** before rollback ************
is TR active true
joind with TR true
is open true
is connected true

******** After rollback ************

is TR active false
joind with TR false
is open true
is connected true

As its evident from this output , after you call tr.rollback() ,

1.Transaction which you started earlier is no longer active.
2.Session gets detached from transaction.
3.Session still remains open.
4.Session still remains connected.

So you can still start new transaction again with this session and it should work fine. hope this answers all your queries about tr.rollback().

Upvotes: 0

Naros
Naros

Reputation: 21163

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.

Upvotes: 2

Related Questions