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.
************************************************************************
****
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
Object result = null;
if (PASSTHROUGH_METHODS.contains(method.getName())) {
try {
result = method.invoke(daoImpl.getDaoInstance(), args);
} catch (Throwable t) {
throw ClassInfo.unwrapThrowable(t);
}
} else {
DaoContext context = daoImpl.getDaoContext();
if (context.isTransactionRunning()) {
// immediately invoke, running inside transaction
try {
result = method.invoke(daoImpl.getDaoInstance(), args);
} catch (Throwable t) {
throw ClassInfo.unwrapThrowable(t);
}
} else {
StandardDaoManager daoManager = daoImpl.getDaoManager();
if (daoManager.isExplicitTransaction()) {
// Just start the transaction (explicit)
try {
context.startTransaction();
result = method.invoke(daoImpl.getDaoInstance(), args);
} catch (Throwable t) {
throw ClassInfo.unwrapThrowable(t);
}
} else {
// Start, commit and end the transaction (autocommit)
try {
context.startTransaction();
result = method.invoke(daoImpl.getDaoInstance(), args);
context.commitTransaction();
} catch (Throwable t) {
throw ClassInfo.unwrapThrowable(t);
} finally {
context.endTransaction();
}
}
}
}
return result;
}