乐趣区

关于spring:Spring事务传播行为

本文出处 Spring 事务流传行为
转载请阐明出处

在 Spring @Transactional 申明式事务有一个项属性 propagation 事务流传行为,是一个 Propagation 枚举类,有 7 种类型,对应不同应用场景。上面说下这些枚举代码含意,在联合代码加深了解,坚固学习。

Spring 属性 阐明
REQUIRED 反对以后事务,如果不存在事务则创立一个新事务。这个 propagation 默认属性
SUPPORTS 反对以后事务,如果不存在事务则依照无事务执行
MANDATORY 反对以后事务,如果不存事务在则抛出异样
REQUIRES_NEW 创立一个新的事务,如果存在以后事务,则将它挂起
NOT_SUPPORTED 无事务执行,如果存在事务将它挂起
NEVER 无事务执行,如果存在以后事务则抛出异样
NESTED 如果以后事务存在,则在嵌套事务中执行, 如果不存在事务就像 REQUIRED 成果

事务流传级别生效

先做一个小试验,写一个长久化的 save 办法,设置成禁用事务,用事务办法去调用它,看会产生什么成果。

    @Transactional(propagation = Propagation.NEVER)
    public void save(Users users){usersRepository.save(users);
    }

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
    }

依照下面字段含意解析,save 办法不反对事务,在以后事务运行会抛出异样。可是执行后果不是意料那样,没有抛出异样,数据写入到数据库了。并且咱们能够在改一次 save 办法,间接抛出一个 RuntimeTime 异样,你会发现后果更加显著。

    @Transactional(propagation = Propagation.NEVER)
    public void save(Users users){usersRepository.save(users);
        throw new RuntimeException("4322");
    }

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
    }

你会发现 save 办法 数据回滚了。

在做多几次这种试验你就会发现,在同一个类中,最外层事务注解属性会笼罩办法内所有事务注解,比方你的外层设置默认事务流传行为,无论调用那种行为都会依照默认属性,外层没有设置事务,调用办法有事务也不会失效的。这个不难理解,实现 Spring 事务一个基于 AOP 的代理类,它依据指标办法注解来加强办法,这个是运行时动静执行的,办法内其余办法没有代理类的性能加强,就相当于一般办法成果了。千万不要在同一个类外面测试事务流传行为,否则你永远都都得不到论断的。

进入办法验证

默认事务

    @Transactional
    public void save(){Employee employee = new Employee();
        employee.setDepartmentId(2);
        employee.setName("Jorry");
        employee.setSalary(60000);
        repository.save(employee);
        throw new RuntimeException("33333");
    }

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
        employeeService.save();}

执行后果:users、employee 写入失败,employee 的办法抛出异样触发回滚,也会导致外层办法回滚。在同一个事务中,只有触发回滚,事务内所有数据操作都会回滚的。

反对事务

    @Transactional(propagation = Propagation.SUPPORTS)
    public void save(){Elimployee employee = new Employee();
        employee.setDepartmentId(2);
        employee.setName("Jorry");
        employee.setSalary(60000);
        repository.save(employee);
    }

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
        employeeService.save();
        throw new RuntimeException("3333");
    }

执行成果: Usres 和 Elimployee 都进行回滚了。SUPPORTS 会退出调用者事务中,和调用者事务是同一个事务,如果在事务中出现异常全副回滚。即便在employeeService.save() 抛出异样, 成果一样的。

开启新事务

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save(){Employee employee = new Employee();
        employee.setDepartmentId(2);
        employee.setName("Jorry");
        employee.setSalary(60000);
        repository.save(employee);
        throw new RuntimeException("3333");
    }

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
        try {employeeService.save();
        }catch (RuntimeException e){}

执行后果:empoyee 回滚,users 写入数据库胜利。要解决 employeeService.save()异样,不然异样会导致 multSave 出现异常事务回滚了。退出一个对照,在把 employeeService.save()改成默认属性,发现 users,employee 都会回滚了,还会抛出一个异样

org.springframework.transaction.UnexpectedRollbackException: Transaction silently rolled back because it has been marked as rollback-only

Spring 官网文档说到如果内部事务(内部调用者不晓得)将事务无提醒地标记为仅回滚,则内部调用者仍会调用 commit。内部调用者须要接管一个,UnexpectedRollbackException 以分明地批示已执行回滚。

强制不应用事务

    @Transactional(propagation = Propagation.NEVER)
    public void save(){Employee employee = new Employee();
        employee.setDepartmentId(2);
        employee.setName("Jorry");
        employee.setSalary(60000);
        repository.save(employee);
    }

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
        employeeService.save();}

执行后果: 两个表都写入失败,employeeService.save() 抛出异样

org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation ‘never’

不反对事务

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void save(){Employee employee = new Employee();
        employee.setDepartmentId(2);
        employee.setName("Jorry");
        employee.setSalary(60000);
        repository.save(employee);
        throw new RuntimeException("33333");
    }

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
        employeeService.save();}

执行后果:employee 胜利写入数据库,employee 将事务挂了,用无事务办法执行,users 受到异样抛出,触发事务回滚。如果你把 employeeService.save()解决一下,两种表操作都写入胜利了。

强制事务

    @Transactional(propagation = Propagation.MANDATORY)
    public void save(){Employee employee = new Employee();
        employee.setDepartmentId(2);
        employee.setName("Jorry");
        employee.setSalary(60000);
        repository.save(employee);
    }

    public void multSave(){Users users = getUsers();
        save(users);
        employeeService.save();}

执行后果: users 胜利写入数据库,employee 写入失败并且抛出异样

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation ‘mandatory’

嵌套事务

    @Transactional
    public void multSave(){Users users = getUsers();
        save(users);
        employeeService.save();}

    @Transactional(propagation = Propagation.NESTED)
    public void save(){Employee employee = new Employee();
        employee.setDepartmentId(2);
        employee.setName("Jorry");
        employee.setSalary(60000);
        repository.save(employee);
    }

执行后果:employeeService.save()抛出一个异样,如同 JPA 的实现不反对嵌套执行,这个看不到成果了。

org.springframework.transaction.NestedTransactionNotSupportedException: JpaDialect does not support savepoints – check your JPA provider’s capabilities

退出移动版