using spring's @Transactional on a method which also makes use of aop:after advice
i was trying to see if there's already a similar question but couldn't find it so, here it is.
we have a legacy code where a single BO makes method calls to many DAOs using reflection. i have modified the code for simplicity.
@Transactional
class EndpointData1DAO implements DAO{
void inserData() {
// insert data 1
}
}
@Transactional
class EndpointData2DAO implements DAO{
void inserData() {
// insert data 2
}
}
class MachoBO {
void handleEverything(String daoName)开发者_JS百科 {
DAO dao = getDAOUsingReflection(daoName);
dao.insertData();
}
}
the problem is, the requirement changed so when insertData() is called on EndpointData1DAO, EndpointData2DAO's insertData has to be called as well.
i could simply add EndpointData2DAO as a member of EndpointData1DAO but that severly violates SRP and makes it ugly.
so i have written an annotation @ExecuteAfter(clazz=EndpointData2DAO.class, method="insertData") which gets an instance of EndpointData2DAO and invokes insertData(), after the method of the class which it annotates is executed, by using aop:after, so that given
@Transactional
@ExecuteAfter(clazz=EndpointData2DAO.class, method="insertData")
class EndpointData1DAO implements DAO{
void inserData() {
System.out.println("insert1");
}
}
@Transactional
class EndpointData2DAO implements DAO{
void inserData() {
System.out.println("insert2");
}
}
class MachoBO {
void handleEverything(String daoName) {
DAO dao = getDAOUsingReflection(daoName);
dao.insertData();
}
1 2 will be printed out upon calling machoBO.handleEverthing("Data1");
now my question is, will insertData() of EndpointData1DAO and EndpointData2DAO be in the same physical transaction? in other words, will a runtime exception in EndpointData2DAO's insertData() rollback the data inserted by EndpointData1DAO' insertData()?
many thanx in advance~!!
I found the answer by actually running a test.
By executing the following code, I was able to find out the name of the currently running transaction.
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Class tsmClass = contextClassLoader.loadClass("org.springframework.transaction.support.TransactionSynchronizationManager");
String transactionName = (String) tsmClass.getMethod("getCurrentTransactionName", null).invoke(null, null);
System.out.println(transactionName);
and figured out that when I put @Transactional on MachoBO as below,
@Transactional
class MachoBO {
void handleEverything(String daoName) {
DAO dao = getDAOUsingReflection(daoName);
dao.insertData();
}
since the @Transactional has a "method scope",
when machoBO.handleEverthing("Data1");
is called,
inserData() of both DAOs execute under the transaction name "MachoBO.handleEverthing".
However, when the MachoBO is NOT annotated with @Transactional, inserData() of both DAOs DO NOT share the same method scope, & therefore, get executed under seperate transactions, namely "EndpointData1DAO.inserData" and "EndpointData2DAO.insertData".
It should be noted though(although obvious) that in the case of when a DAO is annotated with @Transactional with the propagation set to REQUIRES_NEW, the insertData() of the DAO runs in a seperate transaction.
精彩评论