开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜