Prashanth, Your suggestion is precisely what I did on a previous project. (The "service delegate" mentioned below.) I had a whole slug of methods whose sole responsibility was to start and end transactions, and it got cumbersome. For example, I might have an updateWidget() method in a service layer class. I then would also have an updateWidget() in the "service delegate" to provide the transaction handling which turns around and calls updateWidget() in the service layer... a proliferation of methods.
It is this proliferation of methods that I want to get away from. -----Original Message----- From: Prashanth Sukumaran [mailto:[EMAIL PROTECTED] Sent: Thursday, August 18, 2005 10:15 AM To: [email protected] Subject: RE: Transaction question Hi, Do we really have to do all this in the name of reusability. Can't you change the way you code? Can't you overload/refactor a method and have the transaction externalized. Assume you have methodA startTransaction(); // do some business logic. callDAO.doSomething(); endTransaction(); Instead change it to methodA [ // All that methodA is used is for now Transaction Encapsulation and not anything else. startTransaction() methodB endTransaction() ] methodB [ // do some business logic. callDAO.doSomething(); ] In a different service manager instead of calling the methodA and hence having nested transactions, can't you call methodB instead. Rgds Prashanth Sukumaran. --- "Barnett, Brian W." <[EMAIL PROTECTED]> wrote: > 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: [email protected] > 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/[email protected]/msg0 > 25 > 80.html > > http://www.mail-archive.com/[email protected]/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: '[email protected]' > 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. > **************************************************************************** > ____________________________________________________ Start your day with Yahoo! - make it your home page http://www.yahoo.com/r/hs **************************************************************************** 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. ****************************************************************************
