IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> spring事务失效的11种场景 -> 正文阅读

[Java知识库]spring事务失效的11种场景

1 访问权限问题:

java的访问权限有4种:private、default、protected、public,它们的权限从左到右,以此变大。如果在开发中,将事务方法定义了错误的访问权限,则事务功能会失效。

@Service
public class EmpService {

    @Transactional
    private void add(UserModel userModel){
        saveData(userModel);
    }
}

如上:add方法的权限被定义成了private,这样会导致事务失效,spring要求被代理方法必须是public的。、

在Spring源码中,如果目标方法不是public,则TransactionAttribute返回null,不支持事务。

2 方法用final修饰

@Service
public class EmpService {

    @Transactional
    public final void add(UserModel userModel){
        saveData(userModel);
    }
}

放方法被final修饰时,也会导致事务失效。

因为spring事务底层是用了aop,用了jdk的动态代理或者cglb的动态代理,会帮我们生成代理类,在代理类中实现事务功能。

如果某个方法被final修饰了,那么在代理类中,就无法重新该方法,而添加事务功能。

注意:如果某个方法被static修饰,同样也无法通过动态代理,变成事务方法。

3 直接调用内部方法

@Service
public class EmpService {

    @Transactional
    public void add(UserModel userModel){
        saveData(userModel);
        updateSataus(userModel);
    }


    @Transactional
    public void updateSataus(UserModel userModel){
        doSomething();
    }
}

由上可知:在事务方法add可知,它直接调用了updateStatus方法,由2可知:方法拥有事务的能力是因为spring aop中生成了代理对象,但是直接调用updateStatus方法不会直接生成事务。但是可以直接将该类直接注入进来,比如:

@Service
public class EmpService {

    private EmpService empService;

    @Transactional
    public void add(UserModel userModel){
        saveData(userModel);
        empService.updateSataus(userModel);
    }


    @Transactional(rollbackFor = Exception.class)
    public void updateSataus(UserModel userModel){
        doSomething();
    }
}

这样事务就生效了,也不会穿生循环依赖的问题。

4 未被Spring管理

public class EmpService {


    @Transactional
    public void add(UserModel userModel){
        saveData(userModel);
        updateSataus(userModel);
    }
    
}

如图:没有将该类交给spring管理

5 多线程调用

????????由以下代码可知:在add()事务方法里面,调用了updateStatus事务方法,但是updateStatus事务方法是在另外一个线程中调用的。这样就导致了两个方法不在同一个线程中,获取到了数据库连接不一样,从而是两个不同的事务,如果updateStatus方法中抛出了异常,add方法是不会回滚的

@Service
public class EmpService {

    @Autowired
    private OrderService orderService;


    @Transactional
    public void add(UserModel userModel){

        new Thread(()->{
            orderService.updateSataus();
        }).start();
    }

}

@Service
public class OrderService{

    @Transactional
    public void updateSataus(){
        System.out.println("======================");
    }

}

????????spring的事务是通过数据库的连接来实现的。当前线程中保存了一个map,key是数据源,value是数据库连接。同一个事务,指同一个数据库连接,只有拥有同一个事务连接才能保证同时提交和回滚。如果是不同的线程,拿到的数据库连接肯定是不同的。

6 表不支持事务

如果表的引擎是myisam,那么它是不支持事务的,要想支持事务,改成innodb引擎

7 事务没有开启

如果是springBoot项目,那么是事务默认是开启的,但如果是spring项目,需要xml配置

8 事务的传播特性

如果事务的传播特性设置错了,事务也会失效。如下:propagation = Propagation.NEVER这种类型的传播特性不支持事务,如果有事务会抛出异常。

目前只有这三种传播特性才会创建新事物:REQUIRED、REQUIRES_NEW、NESTED

@Service
public class EmpService {


    @Transactional(propagation = Propagation.NEVER)
    public void add(UserModel userModel){
        saveData(userModel);
        updateSataus(userModel);
    }

}

9 自己吞了异常

事务不会回滚,最常见的问题是:开发者在代码中手动try...catch了异常。如下:

@Service
public class EmpService {


    @Transactional
    public void add(UserModel userModel){
        try {
            saveData(userModel);
            updateSataus(userModel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

这种情况下,因为开发者自己捕获了异常、又没有手动抛出

10 手动抛了别的异常

如果抛的异常不正确,事务也不会回滚

@Service
public class EmpService {


    @Transactional
    public void add(UserModel userModel) throws Exception {
        try {
            saveData(userModel);
            updateSataus(userModel);
        } catch (Exception e) {

            throw new Exception(e);
        }
    }

}

因为Spring事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的非运行时异常,它不会回滚。

11 自定义会滚异常

如果在使用@Transactional注解声明事务时,有时想自定义回滚异常,spring也是支持的。可以通过设置rollbackFor参数,来完成这个功能。如下:

@Service
public class EmpService {


    @Transactional(rollbackFor = BusinessException.class)
    public void add(UserModel userModel) {
            saveData(userModel);
            updateSataus(userModel);
    }

}

但是如果在程序执行过程中,出现了sql异常,但是sql异常并不属于我们定义的BusinessException异常,所以事务也不会回滚

延伸:

1 嵌套事务导致多回滚了怎么办?

@Service
public class EmpService {

    @Autowired
    private OrderService orderService;


    @Transactional
    public void add(UserModel userModel) {
        saveData(userModel);
        orderService.updateSataus();
    }

}

@Service
public class OrderService(){

    @Transactional(propagation = Propagation.NESTED)
    public void updateSataus(){
        System.out.println("======================");
    }
}

如果说对于这样的代码。如果saveData执行成功了,updataStatus执行失败了,那么整个add方法就会回滚。那么之前saveData执行成功的这个方法也会回滚。

那如何只让报错的方法进行回滚呢?只需要将报错的方法抓取异常就OK了。如下:

@Service
public class EmpService {

    @Autowired
    private OrderService orderService;


    @Transactional
    public void add(UserModel userModel) {
        saveData(userModel);
        try {
            orderService.updateSataus();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

@Service
public class OrderService(){

    @Transactional(propagation = Propagation.NESTED)
    public void updateSataus(){
        System.out.println("======================");
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-30 08:33:07  更:2022-04-30 08:34:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:12:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码