1.问题1
今天在JUnit单元测试中测试接口时,突然发现idea写入数据库成功,但是数据库中没有数据
@Slf4j
@Rollback
@Transactional
class ShippingServiceImplTest extends MallApplicationTests {
@Autowired
private ShippingService shippingService;
private Integer uid = 1;
@Test
public void add() {
ShippingForm form = new ShippingForm();
form.setReceiverName("Arion");
form.setReceiverAddress("江苏南京");
form.setReceiverCity("北京");
form.setReceiverMobile("12212345678");
form.setReceiverPhone("010123456");
form.setReceiverProvince("北京");
form.setReceiverDistrict("海淀区");
form.setReceiverZip("000000");
ResponseVo<Map<String, Integer>> responseVo = shippingService.add(uid, form);
log.info("result={}", responseVo);
}
}
去掉@Rollback注解后,idea中事务正常执行,mysql数据库中依然是没有数据的,查看日志发现
[main] INFO o.s.t.c.t.TransactionContext - Rolled back transaction for test:
明显事务虽然执行成功了但是回滚了,仔细一看问题出在@Transactional,spring支持声明式事务,通过AOP实现实现用户操作和具体的事务解耦,加上该注解后,方法执行前创建一个事务,当方法结束后回滚该事务,这就是为什么idea中事务是执行成功的,最后数据库找中没有数据。
需要注意的是:
事务回滚后主键id不会随着事务的回滚而删除
2.注解失效
执行如下的test方法时,不会报错,证明方法a的注解是没有生效的。
原因在于spring中的@Transactional注解是通过AOP的机制来实现的,首先是产生一个代理对象,然而在执行父类的a方法时,是通过被代理的对象(普通对象)行的,也就是所谓的普通对象,然而普通对象在执行时不会判断方法上是否有事务的注解,因此不生效。
2.1 解决办法1-拆分类
将要执行的a方法单独拆成一个类,然后通过自动注入来调用,因为单独拆分的这个类也是有事务的,所以要进行AOP生成代理对象,最终容器中放的是代理对象,自动注入拿到的bean也是被代理后的,因此可以执行事务。
2.2 直接通过代理对象执行a方法
因为这个时候执行的a方法是代理对象执行的,而不是普通方法执行的
版权归原作者 Arion-ren 所有, 如有侵权,请联系我们删除。