先看代码,你觉得运行结果是什么?
java
public class TestService {
@Autowired
private TestService service;
@Transactional
public void test31() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test1").build();
infOrdersmesInMapper.insert(in);
try {
service.test32();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional
public void test32() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test2").build();
infOrdersmesInMapper.insert(in);
// 异常代码
System.out.println("".substring(4));
}
}
答案是test31插入了一条数据,test32也插入了一条数据。
往下看......
一、首先要确保注解是生效的
示例一:
java
public class TestService1 {
@Autowired
private TestService2 service2;
@Transactional // 生效
public void test1(){
service2.test2();
}
}
public class TestService2 {
@Transactional // 不生效
public void test2() {
System.out.println("test2");
}
}
这里的test1的@Transactional生效,test2()的@Transactional不生效,嵌套时,只有最外层的生效。
示例二:
java
public class TestService1 {
public void test1(){
test2();
}
@Transactional // 不生效
public void test2() {
System.out.println("test2");
}
}
这里的test2()的@Transactional不生效,不是代理类调用时不生效
示例三:
java
public class TestService1 {
@Autowired
private TestService1 service;
public void test1(){
service.test2();
}
@Transactional // 生效
public void test2() {
System.out.println("test2");
}
}
这里自己注入自己,就生效了,因为@Transactional是通过spring的aop来实现的,spring在创建Bean的时候会生成一个代理类,aop只对代理类生效,所以要么通过获取代理类来实现,因为spring自身是解决了循环依赖的问题,所以最简单的方式就是注入自己来实现。
二、代码异常时,执行顺序
从发生异常的地方开始,往上抛
1、如果先遇到try catch,那么就被catch住(如果catch里面不再往外抛异常,那就不会被事务抓到)
2、如果先遇到事务,那就会回滚
三、发生回滚时,哪些代码会被回滚?
会回滚从生效的@Transactional下面的所有内容,包含try catch内容
四、示例
示例一
java
@Transactional
public void test31() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test1").build();
infOrdersmesInMapper.insert(in);
try {
service.test32();
} catch (Exception e) {
e.printStackTrace();
}
// 异常代码
System.out.println("".substring(4));
}
@Transactional
public void test32() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test2").build();
infOrdersmesInMapper.insert(in);
}
结果是,test31的正常代码和test32的正常代码回滚。这里的test31的@Transactional有效,执行异常代码时,会回滚test31里面包含的所有内容,包括try catch里面的test32的内容
示例二
java
public void test31() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test1").build();
infOrdersmesInMapper.insert(in);
try {
service.test32();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional
public void test32() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test2").build();
infOrdersmesInMapper.insert(in);
// 异常代码
System.out.println("".substring(4));
}
结果是,test31的正常代码,执行成功,test32的正常代码被回滚
示例三,文章开头的例子
java
public class TestService {
@Autowired
private TestService service;
@Transactional
public void test31() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test1").build();
infOrdersmesInMapper.insert(in);
try {
service.test32();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional
public void test32() {
// 正常代码
InfOrdersmesIn in = InfOrdersmesIn.builder().zbguid(SnowflakeIdWorker.getSnowflakeId()).zernam("test2").build();
infOrdersmesInMapper.insert(in);
// 异常代码
System.out.println("".substring(4));
}
}
结果是,test31的正常代码执行成功,test32的正常代码也执行成功。这里容易混淆,因为test31的@Transactional生效,但是并没有抓到异常,而是被catch住了,故当执行test32异常时,并不会回滚test32执行成功的代码。
像test32的@Transactional是无效的这种代码,在项目中也比较常见,比如某些方法被其他方法复用时。
总结
1、确保注解生效