использование spring’s @Transactional в методе, который также использует aop: after advice

#java #spring #annotations #aop #transactional

#ява #spring #аннотации #аоп #транзакционный #java #aop

Вопрос:

я пытался посмотреть, есть ли уже подобный вопрос, но не смог его найти, так что, вот он.

у нас есть устаревший код, в котором один BO выполняет вызовы методов для многих DAO, используя отражение. я изменил код для простоты.

 @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) {
   DAO dao = getDAOUsingReflection(daoName);
   dao.insertData();
 }
}
  

проблема в том, что требование изменилось, поэтому, когда insertData () вызывается в EndpointData1DAO, также должны вызываться insertData EndpointData2DAO.

я мог бы просто добавить EndpointData2DAO в качестве члена EndpointData1DAO, но это серьезно нарушает SRP и делает его уродливым.

итак, я написал аннотацию @ExecuteAfter (clazz=EndpointData2DAO.class , method=»insertData»), который получает экземпляр EndpointData2DAO и вызывает insertData() после выполнения метода класса, который он аннотирует, с помощью aop:after, так что данный

 @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
будет распечатан при вызове machoBO.handleEverthing(«Data1»);

теперь мой вопрос в том, будет ли insertData() EndpointData1DAO и EndpointData2DAO находиться в одной физической транзакции? другими словами, будет ли исключение во время выполнения в программе EndpointData2DAO insertData() откатывать данные, вставленные EndpointData1DAO’ insertData()?

заранее большое спасибо~!!

Ответ №1:

Я нашел ответ, фактически запустив тест.

Выполнив следующий код, я смог узнать имя текущей транзакции.

 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);
  

и понял, что, когда я вставил
@Transactional для MachoBO, как показано ниже,

 @Transactional
class MachoBO {
 void handleEverything(String daoName) {
   DAO dao = getDAOUsingReflection(daoName);
   dao.insertData();
 }
  

поскольку @Transactional имеет «область действия метода»,
когда machoBO.handleEverthing("Data1"); вызывается,
inserData() обоих DAO выполняется под именем транзакции «MachoBO.handleEverthing».

Однако, когда MachoBO НЕ помечен @Transactional, inserData() обоих DAO НЕ использует одну и ту же область применения метода, и поэтому выполняется в рамках отдельных транзакций, а именно «EndpointData1DAO.inserData» и «EndpointData2DAO.insertData».

Однако следует отметить (хотя это и очевидно), что в случае, когда DAO аннотируется с помощью @Transactional с набором для распространения REQUIRES_NEW , insertData() DAO выполняется в отдельной транзакции.