использование Spring @Transactional для метода, который также использует aop: после совета - PullRequest
3 голосов
/ 14 июня 2011

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

У нас есть устаревший код, где один 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.

iмог бы просто добавить 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 находиться в одной физической транзакции?другими словами, будет ли исключение времени выполнения в методе insertData () EndpointData2DAO откатывать данные, вставленные функцией EndDodeData1DAO 'insertData ()?

за много раз спасибо ~ !!

1 Ответ

0 голосов
/ 17 июня 2011

Я нашел ответ, выполнив тест.

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

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"); называется, insertData () обоих DAO выполняется под именем транзакции "MachoBO.handleEverthing".

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

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

...