-->
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.  [ 6 posts ] 
Author Message
 Post subject: Nested transactions possible?
PostPosted: Thu Nov 25, 2004 6:54 am 
Newbie

Joined: Thu Nov 25, 2004 5:46 am
Posts: 2
I need to use nested transactions. Is that possible? Suppose I have something like this:

Code:
public class User {
  public void deductMoney() {
    Transaction tx = session.beginTransaction();
    setMoney(getMoney() - 10));
    tx.commit()
  }

  public void buyStuff() {
    Transaction tx = session.beginTransaction();
    stuff = getStuff();
    deductMoney();
    tx.commit();
  }



The call to deductMoney() in buyStuff() should not result i a new transaction, rather it should join the existing transaction that was started in buyStuff().
The API doc for Session.beginTransaction() indicates that it should work this way: "If a new underlying transaction is required, begin the transaction. Otherwise continue the new work in the context of the existing underlying transaction".
Using JDBCTransactionFactory I get "java.sql.SQLException: Can't call commit when autocommit=true".
Using JTATransactionFactory I get "java.lang.IllegalStateException: Can't commit outside of a transaction.
Either the UserTransaction.begin() is missing or the transaction has already been committed or rolled back."
For JTA I've just configured transaction.factory_class in the config file. Maybe there is something else I have to do to get JTA transactions to work? I'm using resin-ee 2.1 as application server.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 25, 2004 7:00 am 
Regular
Regular

Joined: Tue Oct 12, 2004 9:02 am
Posts: 66
Location: Italy
If you use ThreadLocal transactions, you can start transactions wihtout care to this:

public class HibernateUtil {
...
private static final ThreadLocal threadTransaction = new ThreadLocal();

..
/**
* Start a new database transaction.
*/
public static void beginTransaction() throws InfrastructureException {
Transaction tx = (Transaction) threadTransaction.get();

try {
if (tx == null) {
tx = getSession().beginTransaction();
threadTransaction.set(tx);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
}

/**
* Commit the database transaction.
*/
public static void commitTransaction() throws InfrastructureException {
Transaction tx = (Transaction) threadTransaction.get();

try {
if ((tx != null) && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.commit();
}

threadTransaction.set(null);
} catch (HibernateException ex) {
rollbackTransaction();
throw new InfrastructureException(ex);
}
}

/**
* Commit the database transaction.
*/
public static void rollbackTransaction() throws InfrastructureException {
Transaction tx = (Transaction) threadTransaction.get();

try {
threadTransaction.set(null);

if ((tx != null) && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.rollback();
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
} finally {
closeSession();
}
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 25, 2004 9:32 am 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
Quote:
if ((tx != null) && !tx.wasCommitted() && !tx.wasRolledBack())


i don't like wasCommitted method because as said in the javadoc:
Quote:
Check if this transaction was successfully committed. This method could return false even after successful invocation of commit().


and i've tested it with Oracle, sometimes it returns true after a succesfull commit, sometimes not. ;(

_________________
Anthony,
Get value thanks to your skills: http://www.redhat.com/certification


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 26, 2004 4:57 am 
Newbie

Joined: Thu Nov 25, 2004 5:46 am
Posts: 2
agori wrote:
public static void beginTransaction() throws InfrastructureException {
Transaction tx = (Transaction) threadTransaction.get();

try {
if (tx == null) {
tx = getSession().beginTransaction();
threadTransaction.set(tx);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
}

public static void commitTransaction() throws InfrastructureException {
Transaction tx = (Transaction) threadTransaction.get();

try {
if ((tx != null) && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.commit();
}

threadTransaction.set(null);
} catch (HibernateException ex) {
rollbackTransaction();
throw new InfrastructureException(ex);
}
}



I hoped that Hibernate would manage nested transactions for you, so you don't have to build the functionality yourself.

By the way, Will the code you posted work? The first encountered commitTransaction() will commit the transaction, and not the one that corresponds to the first beginTransaction(). I guess you have have to keep track of the nesting depth and only commit() when you are at the outer most transaction.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 26, 2004 5:01 am 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
There are no nested transactions in Java, at least not in common systems. The ThreadLocal is just a nice way to give you the _same_ transaction object whenever you ask in the _same_ thread of execution.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 26, 2004 5:30 am 
Regular
Regular

Joined: Tue Oct 12, 2004 9:02 am
Posts: 66
Location: Italy
ps wrote:
I guess you have have to keep track of the nesting depth and only commit() when you are at the outer most transaction.


This code is for the "session per request pattern" (right?), so when user perform a request, a filter will open the session(but anyway it is better to posticipate the opening of the session in your DAO), and at the end of the request the same filter will close the session, and commit transactions calling commit.
So you don't have to commit in your DAO or classes otherwise it will commit everything too early.

If you need to commit several times in the same request, I think you should keep track of the nesting level of the transaction, otherwise i think you don't need it.
What kind of application are you programming?
CaveatEmptor example implments this patterns.

p.s sorry for my english!


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 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.