测试1: @Transactional方法调用 非@Async 方法
第一个类,一个普通的方法
@Service
@Slf4j
public class AsyncTest {
public void testAsync(){
if(log.isInfoEnabled()){
log.info("testAsync线程名字:{}",Thread.currentThread().getName());
}
// 模拟出现异常,观察第二个类中的相关方法是否会回滚
throw new RuntimeException("模拟异常");
}
}
第二个类,有一个加了@Transactional(rollbackFor = Exception.class)的方法,调用个第一个类中的@Async注解的方法
@Slf4j
@Service
public class TransactionalTest {
@Autowired
private CommodityService commodityService;
@Autowired
private AsyncTest asyncTest;
@Transactional(rollbackFor = Exception.class)
public void testTransactional(){
CommodityVO test = new CommodityVO("测试商品biubiubiubiubiu", new BigDecimal("10.00"), 10);
// 数据库操作
commodityService.addCommodity(test);
if(log.isInfoEnabled()){
log.info("testTransactional线程名字:{}",Thread.currentThread().getName());
}
// 执行第一个类中的方法
asyncTest.testAsync();
}
}
测试方法:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisApplicationTests {
@Autowired
private TransactionalTest annotationTest;
@Test
public void contextLoads() {
annotationTest.testTransactional();
}
}
结果:
数据库中不会插入新数据,证明事务回滚
测试2: @Transactional方法调用@Async方法
第一个类,有一个加了@Async注解的方法
@Service
@Slf4j
public class AsyncTest {
@Async
public void testAsync(){
if(log.isInfoEnabled()){
log.info("testAsync线程名字:{}",Thread.currentThread().getName());
}
// 模拟出现异常,观察第二个类中的相关方法是否会回滚
throw new RuntimeException("模拟异常");
}
}
第二个类,有一个加了@Transactional(rollbackFor = Exception.class)的方法,调用个第一个类中的@Async注解的方法
@Slf4j
@Service
public class TransactionalTest {
@Autowired
private CommodityService commodityService;
@Autowired
private AsyncTest asyncTest;
@Transactional(rollbackFor = Exception.class)
public void testTransactional(){
CommodityVO test = new CommodityVO("测试商品1号", new BigDecimal("10.00"), 10);
// 数据库操作
commodityService.addCommodity(test);
if(log.isInfoEnabled()){
log.info("testTransactional线程名字:{}",Thread.currentThread().getName());
}
// 执行第一个类中的方法
asyncTest.testAsync();
}
}
测试方法:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MybatisApplicationTests {
@Autowired
private TransactionalTest annotationTest;
@Test
public void contextLoads() {
annotationTest.testTransactional();
}
}
结果:
数据库中仍然插入了新数据,回滚失败
原因(From ChatGPT4.0):
当一个带有 @Transactional
注解的方法直接调用一个带有 @Async
注解的方法时,可能会出现事务失效和异常回滚不生效等问题。
这是因为异步执行(即在新线程中执行)导致原始调用线程的事务上下文无法传递到新线程中。所以,在新线程进行数据库操作时将不受原有事务控制。
要避免这些问题,请确保需要保证事务性和需要异步处理之间没有直接依赖关系,并尽量将它们拆分成独立功能模块或服务。