一、背景
- 方法添加了@Transactional注解,为什么事务不生效
二、步骤
- 测试用表结构
CREATE TABLE `test_aop` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 事务方法所在类
@Component @Slf4j public class AopDataService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private AopDataService aopDataService; // 写入数据 @Transactional public void insert(String value) { jdbcTemplate.update("insert into test_aop(name) values('" + value + "')"); } // 写入数据后抛异常 @Transactional public void insertAndRollback(String value) { log.info("insertAndRollback {}", value); jdbcTemplate.update("insert into test_aop(name) values('" + value + "')"); throw new RuntimeException(); } // 使用this调用事务方法 public void invokeMethod() { try { this.insertAndRollback("invokeMethod"); // 这里的this就是AopDataService,不是代理对象。 // 所以调用的insertAndRollback方式是原生方法,不是@Transactional注解代理后的对象 } catch (RuntimeException ex) { log.warn("Catch an Exception in invokeMethod()"); } } // 使用this.aopDataService调用事务方法 public void invokeMethodAutowired() { try { this.aopDataService.insertAndRollback("invokeMethodAutowired"); // this.aopDataService 代理对象,事务生效 } catch (RuntimeException ex) { log.error("Catch an Exception in invokeMethodAutowired()"); } } // 使用getBean调用事务方法 public void invokeMethodGetBean() { try { AopDataService aopDataService = SpringUtil.getBean("aopDataService", AopDataService.class); aopDataService.insertAndRollback("invokeMethodGetBean"); // aopDataService 代理对象,事务生效 } catch (RuntimeException ex) { log.warn("Catch an Exception in invokeMethodGetBean()"); } } }
- 调用事务方法单元测试
@Autowired private AopDataService aopDataService; // 写入成功(this.aopDataService是代理对象) @Test public void insert() { this.aopDataService.insert("insert"); } // 抛异常,数据写入不成功(this.aopDataService是代理对象) @Test public void insertAndRollback() { this.aopDataService.insertAndRollback("insertAndRollback"); } // 抛异常,数据写入成功(invokeMethod方法内未使用AopDataService代理对象) @Test public void invokeMethod() { this.aopDataService.invokeMethod(); } // 抛异常,数据写入不成功(invokeMethodAutowired方法内使用了AopDataService代理对象) @Test public void invokeMethodAutowired() { this.aopDataService.invokeMethodAutowired(); } // 抛异常,数据写入不成功(invokeMethodGetBean方法内使用了AopDataService代理对象) @Test public void invokeMethodGetBean() { this.aopDataService.invokeMethodGetBean(); }
三、总结&问题
- invokeMethod通过 this方式调用insertAndRollback方法,该方法抛异常但是写入成功,原因是
这里的this就是 AopDataService,不是代理对象。
所以调用的insertAndRollback方式是原生方法,不是@Transactional注解代理后的对象
- invokeMethodAutowired、invokeMethodGetBean调用成功是因为都使用的AopDataService代理对象