【数据库】@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用法一样

相关推荐
chengpei14711 分钟前
chrome游览器JSON Formatter插件无效问题排查,FastJsonHttpMessageConverter导致Content-Type返回不正确
java·前端·chrome·spring boot·json
五味香13 分钟前
Java学习,List 元素替换
android·java·开发语言·python·学习·golang·kotlin
Joeysoda16 分钟前
Java数据结构 (从0构建链表(LinkedList))
java·linux·开发语言·数据结构·windows·链表·1024程序员节
扫地僧00919 分钟前
(Java版本)基于JAVA的网络通讯系统设计与实现-毕业设计
java·开发语言
天乐敲代码20 分钟前
JAVASE入门九脚-集合框架ArrayList,LinkedList,HashSet,TreeSet,迭代
java·开发语言·算法
endcy201643 分钟前
IoTDB结合Mybatis使用示例(增删查改自定义sql等)
java·mybatis·iotdb
带刺的坐椅1 小时前
Solon Cloud Gateway 开发:导引
java·gateway·solon·solon cloud
securitor1 小时前
【java】IP来源提取国家地址
java·前端·python
计算机学姐1 小时前
基于微信小程序的民宿预订管理系统
java·vue.js·spring boot·后端·mysql·微信小程序·小程序
云和恩墨1 小时前
云计算、AI与国产化浪潮下DBA职业之路风云变幻,如何谋破局启新途?
数据库·人工智能·云计算·dba