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]/msg025
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.
****************************************************************************