Spring 个事务 - 新事务中的异常导致父事务中的回滚
Spring transactions - Exception in new transaction cause rollback in parent one
我正在努力解决用 Propagation.REQUIRES_NEW 注释的方法的奇怪行为。
在方法 placeOrder() 的主体中,最后一个操作是发送可能会引发运行时异常的短信。
我不介意发送短信会抛出异常,所以我不想在 placeOrder() 中开始事务回滚。
方法 sendSms() 有传播 REQUIRES_NEW 所以据我所知,它不应该触发挂起事务的回滚,只有
@Component
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Autowired
private WarehouseService warehouseService;
@Autowired
private SmsClient smsClient;
@Autowired
private UserDao userDao;
@Transactional
@Override
public void placeOrder(PlaceOrderRequest placeOrderRequest) {
Product product = productDao.getById(placeOrderRequest.getProductId());
WarehouseItem warehouseItem = warehouseService.getAvailable(product);
Order order = orderDao.createNew();
order.setProduct(product);
order.setUser(user);
smsClient.sendSms();
}
}
@Component
public class SmsClient {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendSms() {
throwEx();
}
private void throwEx() throws SmsClientException {
throw new SmsClientException();
}
}
这是来自 TransactionManager 的日志:
Creating new transaction with name [ai.optime.springmicroservicetemplate.domain.order.impl.DefaultOrderService.placeOrder]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
Opened new EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@25711903]
Executing DAO method 'getById' from class 'JpaBasedProductDao' with args {1}
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Executing DAO method 'getAvailable' from class 'JpaBasedWarehouseItemDao' with args {1}
HHH000397: Using ASTQueryTranslatorFactory
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Executing DAO method 'createNew' from class 'JpaBasedOrderDao' with args {}
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Executing DAO method 'getById' from class 'JpaBasedUserDao' with args {1}
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Suspending current transaction, creating new transaction with name [ai.optime.springmicroservicetemplate.api.sms.SmsClient.sendSms]
Opened new EntityManager [SessionImpl(1649890926<open>)] for JPA transaction
Exposing JPA transaction as JDBC org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@6f98ca1d]
Initiating transaction rollback
Rolling back JPA transaction on EntityManager [SessionImpl(1649890926<open>)]
Closing JPA EntityManager [SessionImpl(1649890926<open>)] after transaction
Resuming suspended transaction after completion of inner transaction
Initiating transaction rollback
Rolling back JPA transaction on EntityManager [SessionImpl(1447696365<open>)]
Closing JPA EntityManager [SessionImpl(1447696365<open>)] after transaction
你的理解有误。您没有捕获 smsClient.sendSms()
抛出的异常,因此它是从 placeOrder()
抛出的,因此回滚了为此方法启动的事务。
此外,使 sendSms()
具有事务性意义不大,因为发送 SMS 很可能不会与任何事务性资源交互。
我正在努力解决用 Propagation.REQUIRES_NEW 注释的方法的奇怪行为。
在方法 placeOrder() 的主体中,最后一个操作是发送可能会引发运行时异常的短信。
我不介意发送短信会抛出异常,所以我不想在 placeOrder() 中开始事务回滚。
方法 sendSms() 有传播 REQUIRES_NEW 所以据我所知,它不应该触发挂起事务的回滚,只有
@Component
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Autowired
private WarehouseService warehouseService;
@Autowired
private SmsClient smsClient;
@Autowired
private UserDao userDao;
@Transactional
@Override
public void placeOrder(PlaceOrderRequest placeOrderRequest) {
Product product = productDao.getById(placeOrderRequest.getProductId());
WarehouseItem warehouseItem = warehouseService.getAvailable(product);
Order order = orderDao.createNew();
order.setProduct(product);
order.setUser(user);
smsClient.sendSms();
}
}
@Component
public class SmsClient {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendSms() {
throwEx();
}
private void throwEx() throws SmsClientException {
throw new SmsClientException();
}
}
这是来自 TransactionManager 的日志:
Creating new transaction with name [ai.optime.springmicroservicetemplate.domain.order.impl.DefaultOrderService.placeOrder]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
Opened new EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@25711903]
Executing DAO method 'getById' from class 'JpaBasedProductDao' with args {1}
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Executing DAO method 'getAvailable' from class 'JpaBasedWarehouseItemDao' with args {1}
HHH000397: Using ASTQueryTranslatorFactory
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Executing DAO method 'createNew' from class 'JpaBasedOrderDao' with args {}
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Executing DAO method 'getById' from class 'JpaBasedUserDao' with args {1}
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Participating in existing transaction
Found thread-bound EntityManager [SessionImpl(1447696365<open>)] for JPA transaction
Suspending current transaction, creating new transaction with name [ai.optime.springmicroservicetemplate.api.sms.SmsClient.sendSms]
Opened new EntityManager [SessionImpl(1649890926<open>)] for JPA transaction
Exposing JPA transaction as JDBC org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@6f98ca1d]
Initiating transaction rollback
Rolling back JPA transaction on EntityManager [SessionImpl(1649890926<open>)]
Closing JPA EntityManager [SessionImpl(1649890926<open>)] after transaction
Resuming suspended transaction after completion of inner transaction
Initiating transaction rollback
Rolling back JPA transaction on EntityManager [SessionImpl(1447696365<open>)]
Closing JPA EntityManager [SessionImpl(1447696365<open>)] after transaction
你的理解有误。您没有捕获 smsClient.sendSms()
抛出的异常,因此它是从 placeOrder()
抛出的,因此回滚了为此方法启动的事务。
此外,使 sendSms()
具有事务性意义不大,因为发送 SMS 很可能不会与任何事务性资源交互。