• spring事物失效场景


    java 开发中,如果一个请求需要操作多个数据表(增删改),为了确保操作的原子性,数据的一致性,一般需要引入spring事物注解@Transactional。

    事物特性:ACID (原子性 一致性  隔离性 持久性)

    失效场景1: 访问权限不支持  

    java 中访问权限有 private ,default, protect, public ,要想事物生效,spring 要求被代理的方法必须是public修饰的。

    失效场景2:方法用final 修饰

    被final 修饰的方法表示该方法不可被子类重写。 spring 事务底层使用了 aop,通过 jdk 动态代理或者 cglib,帮我们生成了代理类,在代理类中实现的事务功能。但如果某个方法用 final 修饰了,那么在它的代理类中,就无法重写该方法,无法实现事物。

    失效场景3:方法内部调用

    例如: updateStatus 事物并不会生效,updateStatus会被当成add方法的this调用,并没有加入spring 代理中。

    @Service
    public class UserService {
    
        @Autowired
        private UserMapper userMapper;
      
        public void add(UserModel userModel) {
            userMapper.insertUser(userModel);
            updateStatus(userModel);
        }
    
        @Transactional
        public void updateStatus(UserModel userModel) {
            doSameThing();
        }
    }

    解决办法: 使用AopContext.currentProxy() 获取代理对象    ((UserService)AopContext.currentProxy()).updateStatus(userModel);

    失效场景4:多线程调用
    只有拥有同一个数据库连接才能同时提交和回滚。如果在不同的线程,拿到的数据库连接肯定是不一样的,所以是不同的事务。

    失效场景5:数据库表不支持事物
    如果表引擎是myisam 则不支持事物,mysql5之后innodb 取而代之。

    失效场景6:try catch 吞并了异常或抛出了其他异常

     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);
            }
        }
    }

     扩展:

    事物的传播特性:

    (1)REQUIRED 如果当前上下文中存在事务,则加入该事务,如果不存在事务,则创建一个事务,这是默认的传播属性值。

    (2)SUPPORTS 如果当前上下文中存在事务,则支持事务加入事务,如果不存在事务,则使用非事务的方式执行。

    (3)MANDATORY 当前上下文中必须存在事务,否则抛出异常。

    (4)REQUIRES_NEW 每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。

    (5)NOT_SUPPORTED 如果当前上下文中存在事务,则挂起当前事务,然后新的方法在没有事务的环境中执行。

    (6)NEVER 如果当前上下文中存在事务,则抛出异常,否则在无事务环境上执行代码。

    (7)NESTED 如果当前上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务

    脏读,不可重复读,幻读:
     (1)脏读:当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据)。

    (2)不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。

     (3)幻读:在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。

     事物隔离级别:

     mysql 默认的隔离级别是 Repeatable Read 可重复读 ,oracle 默认的隔离级别是 Read Committed 读已提交。

  • 相关阅读:
    vscode clang-format
    MyBatis中比较(大于、小于)符号的转义写法
    byte数组(byte[])与MultipartFile相互转化
    IDEA报错 Error:(24, 35) java: 常量字符串过长
    Nginx中配置反向代理的proxy_pass的不同斜杠的区别
    使用docker-compose一起安装kafka(zookeeper)
    docker启动报错:Failed to Setup IP tables: Unable to enable SKIP DNAT rule
    Xftp设置指定记事本(notepad++)打开文件
    Linux使用docker安装Nginx
    使用openssl生成证书,并通过Nginx配置
  • 原文地址:https://www.cnblogs.com/wlong-blog/p/15386099.html
Copyright © 2020-2023  润新知