首页 > 其他分享 >SpringBoot中@Transactional失效场景

SpringBoot中@Transactional失效场景

时间:2023-12-14 10:55:16浏览次数:40  
标签:事务 SpringBoot Transactional entity Propagation 失效 public

一、背景:

1、需求

  定时器需要定时到“消息通知表”中获取“消息反馈表”中不存在的数据,遍历这些数据,并对每一条数据发起流程,不管发起成功与否都需要往消息反馈表中插入一条该数据的发起结果,若发起成功还需要往“核查案件表”中插入一条该案件的主表数据

2、问题:

  发现在发起流程过程中,抛出了异常,但是事务并没有回滚,“消息反馈表”和“核查案件表”均新增了一条数据

3、service实现类代码:

@Slf4j
@Service
public class XcckServiceImpl implements XcckService {
	@Override
    public void apply() {
        List<ZfappYwxxtzCk> zfappYwxxtzCkList = 
                ywxxtzCkService.findListAndFilter(FileConstant.XCCK_DB_SOURCE, BizTypeEnum.XCCK.getCode());
        zfappYwxxtzCkList.forEach(this::applyXcck);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    protected void applyXcck(ZfappYwxxtzCk entity) {
        try {
            HcajEntity hcajEntity = this.getEntity(entity);
            hcajService.apply(hcajEntity);
            eventBusPost(hcajEntity);
            this.saveYwxxfk(entity.getId(), SystemConstant.ENABLE_FLAG, SystemConstant.EMPTY);
        } catch (Exception ex) {
            this.saveYwxxfk(entity.getId(), SystemConstant.ZERO, ex.toString() + Arrays.toString(ex.getStackTrace()));
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    protected void saveYwxxfk(String ywId, Integer bs, String bg) {
        ywxxfkService.save(
                new YwxxfkModel()
                        .setYwxxtzbId(ywId)
                        .setFkbs(bs)
                        .setYwlx(BizTypeEnum.XCCK.getCode())
                        .setFkbg(bg));
    }
}

二、分析

1、@Transactional失效的场景:

①应用在非public修饰的方法上时,@Transactional失效

jdk动态代理(基于接口)只能访问public方法
(有个疑问,如果是CGLIB动态代理呢?)

②注解属性 propagation 设置错误时,@Transactional失效

Propagation.SUPPORTS:当前存在事务,则加入该事务;否则以非事务方式运行
Propagation.NO_SUPPORTED:以非事务方式运行,若当前存在事务则将事务挂起
Propagation.NEVER:以非事务方式运行,若当前存在事务则抛出异常

③注解属性 rollbackFor 设置错误时,@Transactional失效

默认只回滚 RuntimeException或Error

④在同一个类中,使用this调用带有@Transactional的方法时,@Transactional失效

@Transactional是通过 AOP 来进行事务的管理,调用的方法实际上是 动态代理对象 中的方法,而动态代理对象需要从容器中获取(容器启动后生成并注入动态代理对象),直接调用this调用方法的话就无法通过动态代理对象进行事务管理

⑤异常被catch且没有再次被抛出,@Transactional失效

⑥数据库引擎不支持事务,@Transactional失效

⑦使用多数据源,@Transactional失效

动态代理对象获取的数据库连接还是原来的,需要为不同的数据源配置不同的事务管理器

2、存在的问题

①@Transactional用在protected方法

②在该类中使用this调用带有@Transactional注解的方法

三、解决

1、修改代码

@Slf4j
@Service
public class XcckServiceImpl implements XcckService {

	@Autowired
	//注入自己
	private XcckServiceImpl xcckService;

	@Override
    public void apply() {
        List<ZfappYwxxtzCk> zfappYwxxtzCkList = 
                ywxxtzCkService.findListAndFilter(FileConstant.XCCK_DB_SOURCE, BizTypeEnum.XCCK.getCode());
        zfappYwxxtzCkList.forEach(xcckService::applyXcck);//调用代理对象的方法
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    //修改为public
    public void applyXcck(ZfappYwxxtzCk entity) {
        try {
            HcajEntity hcajEntity = this.getEntity(entity);
            hcajService.apply(hcajEntity);
            eventBusPost(hcajEntity);
            //调用代理对象的方法
            xcckService.saveYwxxfk(entity.getId(), SystemConstant.ENABLE_FLAG, SystemConstant.EMPTY);
        } catch (Exception ex) {
        	//调用代理对象的方法
            xcckService.saveYwxxfk(entity.getId(), SystemConstant.ZERO, ex.toString() + Arrays.toString(ex.getStackTrace()));
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    //修改为public
    public void saveYwxxfk(String ywId, Integer bs, String bg) {
        ywxxfkService.save(
                new YwxxfkModel()
                        .setYwxxtzbId(ywId)
                        .setFkbs(bs)
                        .setYwlx(BizTypeEnum.XCCK.getCode())
                        .setFkbg(bg));
    }
}

2、运行结果

当applyXcck方法出现异常回滚时,消息反馈表仍然会有数据来表明这条数据发起成功与否

标签:事务,SpringBoot,Transactional,entity,Propagation,失效,public
From: https://www.cnblogs.com/congshaoblog/p/17900721.html

相关文章

  • springboot虚拟线程(jdk21,springboot3.2.0)
    1.什么是虚拟线程虚拟线程是JDK21版本正式发布的一个新特性。虚拟线程和平台线程主要区别在于,虚拟线程在运行周期内不依赖操作系统线程:它们与硬件脱钩,因此被称为“虚拟”。这种解耦是由JVM提供的抽象层赋予的。虚拟线程的运行成本远低于平台线程。它们消耗的内存要少得多。这就......
  • 【SpringBootWeb入门-12】MySQL-DDL-图形化工具
    1、章节前言上一篇文章我们讲解了MySQL的安装与配置,以及相关sql命令的执行操作,在演示这些sql语句的时候,我们都是在命令行当中进行操作的,在命令行当中敲写语句很不方便,主要原因有以下几点:无提示:命令行当中输入任何sql语句没有任何提示,全凭记忆,而且很容易敲错代码;操作繁琐:全部的......
  • springboot004旅游路线规划系统(Java毕业设计,附数据库和源码)
    第一章绪论1.1选题背景与研究意义随着社会的不断进步,在居民生活水平提高的同时,人们当前在生活的方方面面也越来越注重服务所带来的体验,随着近几年国家政策大力发展旅游业,旅游景点的建设越来也完善,旅游业的发展速度得到了显著的提升。各大旅行社、旅游景点都不断的推出新的活动计......
  • springboot下文件上传。
    1.本地上传到E盘下的image目录@Slf4j@RestControllerpublicclassUploadController{@PostMapping("/upload")publicResultupload(MultipartFileimage)throwsIOException{log.info("文件上传:{}",image);StringoriginalFilenam......
  • 【转载】SpringBoot2.x使用Assert校验(非单元测试)
    参考https://blog.csdn.net/yangshangwei/article/details/123105926环境环境版本操作windows10JDK11Springboot2.3.12.RELEASE注意引入的包为importorg.springframework.util.Assert;介绍对象和类型断言函数说明notNull()假设对......
  • springboot+VUE——mybatis分页和Element Plus的分页组件实践
    分页只有基础的分页功能,跳转和动态选择每页展示多少条数据的功能可以参考ElementPlus的分页组件自行配置并且传入相应的方法即可!<scriptlang="ts"setup>/***分页变量数据*/constpagination=ref({ current_page:1, // 当前页码,此处默认为第一页 total_data:0......
  • 大公司为什么禁止在SpringBoot项目中使用@Autowired注解?
    Spring官方已不推荐使用Autowired字段/属性注入bean,一些大公司的新项目也明令禁止使用了。所以今天就来跟你们讲下spring框架可以使用的不同类型的依赖注入,以及每种依赖注入的适用情况。一、依赖注入的类型尽管针对springframerwork5.1.3的文档只定义了两种主要的依赖......
  • springboot-micrometer潜在oom问题解决办法
    在服务中起一个监听Prometheus拉取的线程,在拉取完成之后清理调meterMap中内容比较多的tag,我这边是清理调gateway.requests.代码如下:@ComponentpublicclassPrometheusMeterRegistryFactory{@ResourceprivatePrometheusMeterRegistryprometheusMeterRegistry;......
  • springboot+vue小白升级之路14-实现系统公告首页公告展示、springboot+vue小白升级之
    还是接着之前的内容,我把新增的功能代码贴出来,给大家参考学习。数据库droptableifexistsan_user;createtablean_user( idintnotnullauto_incrementprimarykeycomment'主键id', namevarchar(255)notnulluniquecomment'姓名', `password`varchar(255)notnu......
  • springboot+vue小白升级之路13-AOP实现登录、增删改查操作日志管理
    还是接着上一个的内容,我把这个新增的关于日志的功能代码都贴出来,供大家学习参考。数据库数据库droptableifexistsan_log;createtablean_log( idintnotnullauto_incrementprimarykeycomment'主键id', namevarchar(255)notnullcomment'操作内容', log_dateda......