首页 > 编程语言 >【Java技术总结】Spring事务失效总结

【Java技术总结】Spring事务失效总结

时间:2022-10-26 00:33:12浏览次数:52  
标签:总结 Java Service Spring void Transactional class userModel public

  1. 事务方法必须是public,private、protected、default都会失效。
@Service
public class UserService {
    @Transactional
    private void add(UserModel userModel) {
        saveData(userModel);
        updateData(userModel);
    }
}
  1. 被static和final修饰的方法会失效。
    因为事务底层使用了AOP,也就是通过JDK或者CG lib动态代理生成代理类,在代理类中实现的事务功能,被这两个修饰就会导致代理类无法重写该方法而添加事务功能
@Service
public class UserService {
    @Transactional
    private final void add(UserModel userModel) {
        saveData(userModel);
        updateData(userModel);
    }
}
  1. 方法内部调用
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    public void add(UserModel userModel) {
        userMapper.insertUser(userModel);
        updateStatus(userModel);
    }
    
    @Transactional
    private void add(UserModel userModel) {
        saveData(userModel);
        updateData(userModel);
    }
}

如果有这样的场景,可以采用以下方法解决:

  • 重新建一个类,让事务方法与调用方法分开在两个类
    事务,被调用方法类注入进调用类
@Service
public class ServiceA {

    @Autowired
    private ServiceB serviceB;

    public void save(User user) {
        queryData1();
        queryData2();
        serviceB.doSave(user);
    }
}

@Service
public class ServiceB {

    @Transactional(rollbackFor = Exception.class)
    public void doSave(User user) {
        addData1();
        updateData2();
    }
}
  • 自己注入自己,不会有循环依赖问题,但是有坑
@Service
public class ServiceA {

    @Autowired
    private ServiceA serviceA;

    public void save(User user) {
        queryData1();
        queryData2();
        serviceA.doSave(user);
    }
    @Transactional(rollbackFor = Exception.class)
    public void doSave(User user) {
        addData1();
        updateData2();
    }
}
  • 上面的改进版,使用AOPContext.currentProxy()来获取代理对象实现相同功能
@Service
public class ServiceA {

    public void save(User user) {
        queryData1();
        queryData2();
        ((ServiceA)AopContext.currentProxy()).doSave(user);
    }
    @Transactional(rollbackFor = Exception.class)
    public void doSave(User user) {
        addData1();
        updateData2();
    }
}
  1. 未被Spring管理,比如没加@Service注解
//@Service
public class UserService {
    @Transactional
    public void add(UserModel userModel) {
        saveData(userModel);
        updateData(userModel);
    }
}
  1. 多线程调用
    由于Spring事务是通过数据库连接来实现的,每个线程保存了一个map用来记录当前数据库连接,只有拥有同一个数据库连接才能同时的提交和回滚,不同线程拿到的数据库连接不同,是不同事务
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleService roleService;

    @Transactional
    public void add(UserModel userModel) throws Exception {
        userMapper.insertUser(userModel);
        new Thread(() -> {
            roleService.doOtherThing();
        }).start();
    }
}
@Service
public class RoleService {
    
    @Transactional
    public void doOtherThing() {
        System.out.println("保存role表数据");
    }
}
  1. 表不支持事务MyISAM引擎不支持事务
  2. 未开启事务Spring老项目需要手动配置applicationContext.xml里配置开启事务,SpringBoot项目配置数据源会默认开启
  3. 错误的传播特性
    @Transactional注解指定了propagation属性,如果不是7种传播属性中的REQUIRED、REQUIRESNEW、NESTED就会当前事务失效,下面的就会失效
@Service
public class UserService {
    @Transactional(propagation = Propagation.NEVER)
    public void add(UserModel userModel) {
        saveData(userModel);
        updateData(userModel);
    }
}
  1. 自己try…catch了异常,事务不会回滚
    想要Spring正常回滚,必须抛出Spring能够处理的异常,没抛异常,Spring会认为程序正常处理
@Slf4j
@Service
public class UserService {
    @Transactional
    public void add(UserModel userModel) {
        try {
            saveData(userModel);
            updateData(userModel);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
    }
}
  1. 手动抛了别的异常事务也不会回滚
    比如下面手动抛了Exception异常也不会回滚,因为Spring默认只处理RuntimeException和Error,对于普通的Exception不会回滚
@Slf4j
@Service
public class UserService {
    @Transactional
    public void add(UserModel userModel) throws Exception {
        try {
            saveData(userModel);
            updateData(userModel);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            throw new Exception(e);
        }
    }
}

标签:总结,Java,Service,Spring,void,Transactional,class,userModel,public
From: https://www.cnblogs.com/blanset/p/16826938.html

相关文章

  • 多日Java小结
    今天已经是学习Java的第12天了,但是总觉得自己的进度真的很慢,现在还没学到循环,但是感觉前面的知识依然还没有消化,所以先小结一下吧。 首先,记住了Java的基本格式,publicst......
  • Javaweb基础复习------EL表达式+JSTL-if&foreach
    EL表达式------简化JSP页面的Java代码主要功能是------获取数据(语法:${data})举例://ServletDemo1.javapackagecom.example.servlet;importcom.example.pojo.User;i......
  • 使用 JSTL 报错:javax/servlet/jsp/tagext/TagLibraryValidator
    jsp使用jstl,访问页面之后报错,如上图所示。我的Tomcat版本是10.0,导入的jstl是javax.servlet下的,应该导入以下几个包:<dependency><groupId>mysql</groupId>......
  • JavaScript实现 -- 顺序搜索
    顺序搜索顺序搜索是一种寻找某一特定值的搜索算法,按一定的顺序检查数组中每一个元素,直到找到所要寻找的特定值为止。顺序搜索是最简单的一种搜索算法。思路遍历数组,并对......
  • Go中结构体基础知识总结
    什么是结构体结构是表示字段集合的用户定义类型。它可以用于将数据分组为单个单元而不是将每个数据作为单独的值的地方。例如,员工有firstName、lastName和age。将这三个属......
  • java反射机制的作用
    反射(Reflection)是Java程序开发语言的特征之一,它允许运行中的Java程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。反射是一项高级开发人员应该......
  • 使用Spring AOP实现系统操作日志记录
    使用SpringAOP实现系统操作日志记录一、什么是SpringSpring是一个广泛应用的J2EE框架,是针对bean的生命周期进行管理的轻量级容器,主要由SpringCore、SpringAOP、Spri......
  • Java的碎碎念(2)
    p21:1.2软件开发介绍常用的DOS命令(windows+Rcmd)>dir:列出当前目录下的文件以及文件夹>md:创建目录>rd:删除目录>cd:进入指定目录>cd.:退回到上一级目录>cdl:退回到根目录......
  • Java碎碎念(3)
    P24:1.5 Java语言的环境搭建什么是JDK,JREJDK(JavaDevelopmentKitJava开发工具包)JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了J......
  • Java碎碎念(三,hello world + 注释)
    windows不区分大小写且区别中英文java区分大小写 第一个代码文件:classHelloChina{         publicstaticvoidmain(String[]args){   ......