在之前的文章中静秆,我們講過如果有兩個事務,A和B严衬,均是Required new的傳遞類型澄者,而我們在A中調(diào)用B。如果B中拋出了異常(RuntimeException请琳,Spring的事務機制只會補貨RumtimeException)粱挡,而A中將異常進行了catch,則A會拋出以下的錯誤
Exception in thread "main" org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
從而強制將事務進行回滾俄精,Spring采用該機制是為了防止用戶錯誤的將引發(fā)回滾的異常進行捕獲而忘記繼續(xù)拋出询筏。
以下的例子展示了這種情況:
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testTransaction() {
LOGGER.info("start test transaction");
CustApplyTicketService service = ApplicationContextHolder.getBean("transactionService",
TransactionService.class);
Person person = new Person();
person.setName("測試");
service.saveEntitySelective(ticket);
try {
service.testInnerTransaction();
} catch (Exception e) {
LOGGER.error("", e);
}
LOGGER.info("finish test transaction");
}
@Override
@Transactional
public void testInnerTransaction() {
throw new RuntimeException("this is a inner exception");
}
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("conf/applicationContext-test.xml");
TransactionService service = ac.getBean("transactionService", TransactionService.class);
service.testTransaction();
}
那有的時候,我們有這種需求竖慧,我們就是希望A回滾屈留,但是又不想通過這種方式拋出異常來進行。那有沒有不拋出異常的回滾方式呢测蘑?
我們可以通過設置TransactionStatus的rollBackOnly標志位的方式來實現(xiàn)。
比如如下的方式:
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void testTransaction() {
LOGGER.info("start test transaction");
CustApplyTicketService service = ApplicationContextHolder.getBean("transactionService",
TransactionService.class);
Person person = new Person();
person.setName("測試");
service.saveEntitySelective(ticket);
try {
service.testInnerTransaction();
} catch (Exception e) {
LOGGER.error("", e);
// 這部是關鍵
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
LOGGER.info("finish test transaction");
}
@Override
@Transactional
public void testInnerTransaction() {
throw new RuntimeException("this is a inner exception");
}
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("conf/applicationContext-test.xml");
TransactionService service = ac.getBean("transactionService", TransactionService.class);
service.testTransaction();
}
在上面康二,我們并不會收到UnexpectedRollbackException的異常碳胳。而由于我們?nèi)斯さ脑O置了回滾標志,所以數(shù)據(jù)庫仍會進行回滾沫勿。