【数据库】@Transactional用法详解

先看代码,你觉得运行结果是什么?

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、确保注解生效

2、代码异常被生效的注解抓到时,才会回滚

3、回滚时,会回滚注解下面的所有内容

注:@DSTransactional用法一样

相关推荐
only-qi3 小时前
146. LRU 缓存
java·算法·缓存
阿里小阿希4 小时前
Vue3 + Element Plus 项目中日期时间处理的最佳实践与数据库设计规范
数据库·设计规范
xuxie134 小时前
SpringBoot文件下载(多文件以zip形式,单文件格式不变)
java·spring boot·后端
白鹭4 小时前
MySQL源码部署(rhel7)
数据库·mysql
重生成为编程大王5 小时前
Java中的多态有什么用?
java·后端
666和7775 小时前
Struts2 工作总结
java·数据库
还听珊瑚海吗5 小时前
SpringMVC(一)
数据库
中草药z5 小时前
【Stream API】高效简化集合处理
java·前端·javascript·stream·parallelstream·并行流
野犬寒鸦5 小时前
力扣hot100:搜索二维矩阵 II(常见误区与高效解法详解)(240)
java·数据结构·算法·leetcode·面试
zru_96025 小时前
centos 系统如何安装open jdk 8
java·linux·centos