-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 
Author Message
 Post subject: Unexpected result with flush() after rollback()
PostPosted: Wed Feb 22, 2006 5:24 pm 
Newbie

Joined: Wed Feb 22, 2006 4:44 pm
Posts: 2
Could someone please explain this:

1. Open a session and retrieve Customer 1 from db
2. Start transaction
3. Change object and saveOrUpdate()
4. Rollback transaction
5. Flush and close session

6. Open another session
7. Retrieve the same Customer 1 from db
8. Why does Customer 1 show the changes in step 3 ??


I know flushing is not necessary in this example but should it not produce
consistent results.

Thank in advance.


public class FlushAndRollbackTest extends TestCase {

public void testRollbackAndFlush() {
Session session = sessionFactory.openSession();

Customer cust = (Customer) session
.get(Customer.class, 1);

String nameBefore = cust.getName();

session.close();

session = sessionFactory.openSession();

timeString = new Long(System.currentTimeMillis()).toString();

Transaction tx = session.beginTransaction();

cust = (Customer) session.get(Customer.class, 1);
cust.setName(timeString);

session.saveOrUpdate(cust);
tx.rollback();
session.flush(); //either removing this statement or flushing before rollback() seems to produce the expected result.
session.close();

Session session2 = sessionFactory.openSession();
cust = (Customer) session2
.get(Customer.class, 1);

assertEquals(nameBefore, cust.getName()); //THIS FAILS !!

session2.close();

}




private String timeString = "";

private SessionFactory sessionFactory = null;

public void setUp() {
try { sessionFactory = new Configuration().configure(
"hibernate_postgres.cfg.xml").buildSessionFactory();

} catch (Exception e) {
e.printStackTrace();
}
}



}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Feb 23, 2006 1:38 am 
Newbie

Joined: Wed Feb 22, 2006 6:25 pm
Posts: 4
This is taken from Hibernate API documentation:
the contract of Session.flush() method is:

Quote:
Force the Session to flush. Must be called at the end of a unit of work, before commiting the transaction and closing the session (Transaction.commit() calls this method). Flushing is the process of synchronising the underlying persistent store with persistable state held in memory.


I'm guessing that you have autocommit on (becouse you can read inside of first and third session without explictly opening transation) - check your code or config file

Documentation says:
Code:
Database transactions are never optional, all communication with a database has to occur inside a transaction, no matter if you read or write data.


so, if you have

Code:
tx.rollback();

old transaction disposed, changes sent to DB are rolled back, but if autocommit is on - that's a begin of new transaction!

Code:
session.flush();

object is still assotiated with session, so Hibernate will presist it

Code:
session.close

Session.close calls and Transaction.close()
when autocommit is on commit is invoked at the end of transation - and at the result object is presisted and changes are commited

please check this property
hibernate.connection.autocommit in your config file,

according to the Docs - generally using autocommit is anti-pattern

hope this helps you,
I wish you luck,
Dominink


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 11:46 am 
Newbie

Joined: Wed Feb 22, 2006 4:44 pm
Posts: 2
Thanks Dominink for your response.

Autocommit is off
And I did do the second read from within a transaction, I still get the same results.

It looks like my usage of flush() is improper, maybe this behavior can be documented


Here is the modified code:

public class FlushAndRollbackTest extends TestCase {

public void testRollbackAndFlush() throws Exception {
Session session = sessionFactory.openSession();

Customer cust = (Customer) session
.get(Customer.class, 1);

String nameBefore = cust.getName();

session.close();

session = sessionFactory.openSession();

timeString = new Long(System.currentTimeMillis()).toString();

Transaction tx = session.beginTransaction();

cust = (Customer) session.get(Customer.class, 1);
cust.setName(timeString);
System.out.println("Auto commit is: " + session.connection().getAutoCommit());
session.saveOrUpdate(cust);
tx.rollback();
session.flush(); //either removing this statement or flushing before rollback() seems to produce the expected result.
session.close();

Session session2 = sessionFactory.openSession();
tx = session2.beginTransaction();
cust = (Customer) session2
.get(Customer.class, 1);
assertEquals(nameBefore, cust.getName()); //THIS FAILS !!
tx.rollback();
session2.close();

}




private String timeString = "";

private SessionFactory sessionFactory = null;

public void setUp() {
try { sessionFactory = new Configuration().configure(
"hibernate_postgres.cfg.xml").buildSessionFactory();

} catch (Exception e) {
e.printStackTrace();
}
}

}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 27, 2006 11:56 am 
Newbie

Joined: Wed Jun 01, 2005 9:01 am
Posts: 5
Location: Recife, Brasil
Shouldn't you clear() the session after a rollback? Have you already tryed without flushing the session (it will be closed anyway)?

_________________
Ricardo Cavalcanti


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 28, 2006 1:05 am 
Newbie

Joined: Wed Feb 22, 2006 6:25 pm
Posts: 4
As I said before Session.flush() should NOT be called outside of transation. You just use this method in bad context.

Quote:
Must be called at the end of a unit of work, before commiting the transaction and closing the session


Perhaps Hibernate should throw an exception if flush is closed NOT within an transaction.

I've also checked testcase you provided -
these are results:

1) because flush is used outside of transaction - it is not commited
session.flush() causes INSERT/UPDATE SQL to be executed:
Code:
INSERT INTO CUSTOMER VALUES(.........something..........)


2) changes are not commited nor rolled back.

3) what is strange - if flush is used this way - all SQL will be commited / rolled back during next transaction (that might be bit dangerous and breaking rules of ACID)

please try add following code

Code:
session.flush();
session.close();

// --- BEGIN OF FIX ----
Session s = sessionFactory.openSession();
s.beginTransaction();
s.getTransaction().rollback();
s.close();
// --- END OF FIX ---
Session session2 = sessionFactory.openSession();


this time your test will be passed...

and if you try to commit changes in the next transation:
Code:
session.flush();
session.close();

// --- BEGIN OF FIX ----
Session s = sessionFactory.openSession();
s.beginTransaction();
s.getTransaction().commit();  [b]//this will save changes to DB!!![/b]s.close();
// --- END OF FIX ---
Session session2 = sessionFactory.openSession();


changes to customer will be saved!
----------------------
Dominik


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 28, 2006 4:13 am 
Newbie

Joined: Wed Jun 01, 2005 9:01 am
Posts: 5
Location: Recife, Brasil
I'm having quite the same problems with transactions in a JUnit TestCase,: when a test fails, it is rolled back but the test just after this will fail also because of the dirty session. I've already used clear, but doesn't work, The only solution i've found is to undo 'per hand' the job that should be rolled back (this case i must delete some inserted objects).

Why use two sessions? There must be another way to do it! I mean, I don't think it is a bug, just that we must config some variables. Or maybe is just a bug!

_________________
Ricardo Cavalcanti


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 28, 2006 8:19 am 
Newbie

Joined: Wed Feb 22, 2006 6:25 pm
Posts: 4
Quote:
According to the doc we shouldn't call Session.flush() after Transaction.close() unless we start a new transaction.


I provided a "FIX" code only to show that Hibernate works inproperly when flush() is used inproperly - changes made by flush() outside of transaction will be attached to next session and commited or rolled back - that is wrong. I don't treat this code as a solution of the problem. A solution is to use flush() inside of transation not outside.

kvalcanti you said:
Quote:
"Why use two sessions?"


we don't have to... we can do also:

Code:
... session open ....
... main tranasction...
tx.rollback();
session.flush();
//transation 2
tx.begin();
tx.rollback(); //changes made by flush are commited / rolled back here
session.close();


it works but flush() is still used inproperly,

this code is proper and passes provided test:

Code:
... main tranasction...
tx.rollback();

tx.begin();
session.flush();
tx.rollback(); //or tx.commit() but commit does flush anyway.

session.close();


but I still don't see reason why we would we want to push data to DB if we cancel it at the end? On the other hand - tx.commit() - calls flush() automatically.

I also dont understand the use case - in what case you would want to flush session outside of transaction? By the way - Why to call it at all? Transaction.close() flushes session - at least in theory :-).

kvalcanti - can you provide a simple TestCase with problem you've described?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 28, 2006 8:44 am 
Newbie

Joined: Wed Jun 01, 2005 9:01 am
Posts: 5
Location: Recife, Brasil
The TestCase goes like this:

1. begin a transaction
2. save some auxiliar objects that are not cascade-inserted.
3. save the main object
4. commit transaction.
5. begin a new transaction
6. delete the main object
7. delete the auxiliar object in the inverse order of insertion
9. commit transaction

tearDown:
if the transaction was not commited and isActive, then rollback the transaction. Close the session.

the assertions are made between some steps, but all queries are made inside a transaction.

If I provoke a error, for example, not saving one of the auxiliar objects, the test will fail on the "save the main object" step (3). Not only, but the next test in the suite that does the same stuff with another main object will fail too (org.hibernate.StaleStateException: Unexpected row count: 0 expected: 1).

Before, the first fail provoked all the following tests to fail with the same exception above. I then made some improvements in the transactions demarcation within the tests. And now one fail provoke only the first next test to fail.

_________________
Ricardo Cavalcanti


Top
 Profile  
 
 Post subject: Re: Unexpected result with flush() after rollback()
PostPosted: Sat Mar 10, 2012 3:28 am 
Newbie

Joined: Sat Mar 10, 2012 3:27 am
Posts: 1
Hey frndz m looking for updated academic results plz help…

_________________
Result.pk


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.