一、背景
- 方法添加了@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代理对象