Brian, Sorry for the late response, but I've been rather busy.
You are right, my code does not work in the situation you mention. I only tried it with autocommit-semantics, i.e. I never called transactionmethods explicitly. Besides, I use a custom transactionmanager which supports nesting in a similar way as your code. I would not have problems at all *if* iBATIS didn't bind its resource-disposal to transactions (endTransaction). This causes "ResultSet already closed" exceptions when nesting DAO-calls. I would really like to see this solved/fixed/worked around by the devteam, because these people have a good overview of the way transactions/resources work, I obviously do not :) It would also help to have some architectural overview (schema) on the website. Grtz, Niels -----Original Message----- From: Barnett, Brian W. [mailto:[EMAIL PROTECTED] Sent: donderdag 18 augustus 2005 17:51 To: 'user-java@ibatis.apache.org' Subject: RE: Transaction question Niels, Thanks for the info. Maybe I am not totally understanding how your modified code works, but is it meant to handle nested transactions? If a transaction has already been started, then your modified code will simply call invoke. I understand that. What happens when a nested transaction calls commitTransaction()? (Like doSomethingElse() calling doSomething() in the sample code below.) commitTransaction() gets called twice in this example. I believe it will throw an exception. What I was considering was to add a ThreadLocal transactionCounter variable to DaoContext. start, commit and end transaction methods might look something like this: public void startTransaction() { transactionCounter++; // <-- NEW LINE OF CODE if (transactionCounter == 1) { // <-- NEW LINE OF CODE if (state.get() != DaoTransactionState.ACTIVE) { DaoTransaction trans = transactionManager.startTransaction(); transaction.set(trans); state.set(DaoTransactionState.ACTIVE); daoManager.addContextInTransaction(this); } } // <-- NEW LINE OF CODE } public void commitTransaction() { if (transactionCounter == 1) { // <-- NEW LINE OF CODE DaoTransaction trans = (DaoTransaction) transaction.get(); if (state.get() == DaoTransactionState.ACTIVE) { transactionManager.commitTransaction(trans); state.set(DaoTransactionState.COMMITTED); } else { state.set(DaoTransactionState.INACTIVE); } } // <-- NEW LINE OF CODE } public void endTransaction() { try { // <-- NEW LINE OF CODE if (transactionCounter == 1) { // <-- NEW LINE OF CODE DaoTransaction trans = (DaoTransaction) transaction.get(); if (state.get() == DaoTransactionState.ACTIVE) { try { transactionManager.rollbackTransaction(trans); } finally { state.set(DaoTransactionState.ROLLEDBACK); transaction.set(null); } } else if (transactionCounter == 1) { state.set(DaoTransactionState.INACTIVE); transaction.set(null); } } // <-- NEW LINE OF CODE } finally { // <-- NEW LINE OF CODE transactionCounter--; // <-- NEW LINE OF CODE } // <-- NEW LINE OF CODE } The idea being that the transaction related logic only executes when we are dealing with the first transaction bracket that was opened. I haven't actually tried this out, but I think I will. Let me know if you, or anyone else, sees any problems with this approach. Thanks, Brian Barnett -----Original Message----- From: Niels Beekman [mailto:[EMAIL PROTECTED] Sent: Wednesday, August 17, 2005 3:00 PM To: user-java@ibatis.apache.org Subject: RE: Transaction question Hi, I'm facing this exact same problem however in a somewhat different context, see the following archived thread: http://www.mail-archive.com/ibatis-user-java@incubator.apache.org/msg025 80.html http://www.mail-archive.com/user-java@ibatis.apache.org/msg00036.html I recently restarted my investigation into this problem and have tried some hacks in the iBATIS code, the changes were made in DaoProxy.java (which proxies DAO-interfaces to provide transaction-semantics) and DaoContext.java (which handles the transactions itself). Of course this is rather messy, but I really do not like the SavePoint-support mentioned in the thread above, I think it is rather a workaround than a solution. Anyway, my changes (totally unverified, without any guarantees) in package com.ibatis.dao.engine.impl: DaoContext.java, added isTransactionRunning(): public boolean isTransactionRunning() { return transaction.get() != null; } DaoProxy.java, modified invoke(): see attached file. This seems to work pretty good in my case, however further investigation is required. I hope the iBATIS devteam can comment on my solution, whether you think it will work, or when you believe it really sucks :) Greetings, Niels -----Original Message----- From: Barnett, Brian W. [mailto:[EMAIL PROTECTED] Sent: woensdag 17 augustus 2005 22:00 To: 'user-java@ibatis.apache.org' Subject: Transaction question What are some good options to deal with the following: ServiceClass1 public void doSomething() { try { daoManager.startTransaction(); // Write some stuff to a database daoManager.commitTransaction(); } catch (Exception e) { throw e; } finally { daoManager.endTransaction(); } } ServiceClass2 public void doSomethingElse() { try { daoManager.startTransaction(); ServiceClass1 sc1 = new ServiceClass1(); sc1.doSomething(); // Write some stuff to a database daoManager.commitTransaction(); } catch (Exception e) { throw e; } finally { daoManager.endTransaction(); } } The doSomethingElse() method will fail because startTransaction() gets called twice. I need a good way to be able to re-use business logic methods in different, or the same, service layer classes. One thing I have done in the past is create a whole new layer, essentially a service delegate, where I have moved all the transaction logic to. I didn't like that too much because it was just a huge proliferation of methods just to solve the "no nested transaction" problem. I have also passed flags into methods to indicate if a transaction has already been started, but passing flags is messy to say the least. Any great ideas out there? TIA, Brian Barnett ************************************************************************ **** This email may contain confidential material. If you were not an intended recipient, Please notify the sender and delete all copies. We may monitor email to and from our network. ************************************************************************ **** ************************************************************************ **** This email may contain confidential material. If you were not an intended recipient, Please notify the sender and delete all copies. We may monitor email to and from our network. ************************************************************************ ****