SpringBoot项目的事务实现

说明:当业务中的某个功能,需要多个操作组合执行才能完成时(如删除部门,部门下的员工也需要同步删除时),为了保证数据的一致性,需要对这些组合操作添加事务。(参考:http://t.csdn.cn/6PFzL)

(根据部门ID删除员工)

    @Delete("delete from tb_emp where id=#{id}")
    void deleteByDeptId(Integer id);

(根据部门ID删除部门,要求删除部门的同时删除该部门下的所有员工)

    @Delete("delete from tb_dept where id=#{id}")
    void deleteById(Integer id);

Controller层

    @RequestMapping("deleteById")
    public void deleteById(Integer id) {
        // 删除该部门
        deptMapper.deleteById(id);

        // 删除部门对应部门ID的员工
        empMapper.deleteByDeptId(id);

(员工表)

SpringBoot项目的事务实现_第1张图片

(部门表)

SpringBoot项目的事务实现_第2张图片

添加事务

在SpringBoot项目中,可以使用@Transactional,给方法添加事务

    @RequestMapping("deleteById")
    @Transactional
    public void deleteById(Integer id) {
        // 删除该部门
        deptMapper.deleteById(id);

        // 手动添加算数异常
        int i = 1 / 0;

        // 删除部门对应部门ID的员工
        empMapper.deleteByDeptId(id);

程序报错,事务未提交,方法未执行成功
SpringBoot项目的事务实现_第3张图片

去掉异常,删除ID为3的部门

    @RequestMapping("deleteById")
    @Transactional
    public void deleteById(Integer id) {
        // 删除该部门
        deptMapper.deleteById(id);

        // 删除部门对应部门ID的员工
        empMapper.deleteByDeptId(id);
    }

执行成功
SpringBoot项目的事务实现_第4张图片
SpringBoot项目的事务实现_第5张图片

需要注意的是,如果抛出的是Exception异常,而不是RuntimeException异常,事务会失效。

(删除ID为4的部门,部门被删除,员工并未被删除)

    @RequestMapping("deleteById")
    @Transactional
    public void deleteById(Integer id) throws Exception {
        // 删除该部门
        deptMapper.deleteById(id);

        // 手动设置Exception异常
        if (true){
            throw new Exception("发生了错误");
        }

        // 删除部门对应部门ID的员工
        empMapper.deleteByDeptId(id);
    }

因为事务捕捉的异常默认是RuntimeException,即只有发生RuntimeException事务才会回滚。可以在@Tranctionful()注解里添加rollback = Exception.class,表示发生任何异常,都回滚事务。

    @RequestMapping("deleteById")
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Integer id) throws Exception {
        // 删除该部门
        deptMapper.deleteById(id);

        // 手动设置Exception异常
        if (true){
            throw new Exception("发生了错误");
        }

        // 删除部门对应部门ID的员工
        empMapper.deleteByDeptId(id);
    }

事务传播

当事务方法,方法中调用的方法也被事务修饰,此时就存在事务传播。在@Transactional注解中,使用propagation属性设置,常用有以下两个值:

REQUIRED:默认值,表示调用自己的事务执行成功与否,同时也表示自己事务的状态;

REQUIRES_NEW:表示调用自己的事务执行成功与否,不会影响自己事务的执行。

例如在删除部门方法中设置一个删除部门日志方法,部门删除执行成功与否,该日志方法都执行

(DeptLogServiceImpl类,设置该事务的事务传播为:REQUIRES_NEW)

    @Autowired
    private DeptLogMapper deptLogMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertDeptLog(DeptLog deptLog){
        deptLogMapper.insert(deptLog);
    }

(DeptLogMapper类)

    @Insert("insert into dept_log(create_time,description) values(#{createTime},#{description})")
    void insert(DeptLog log);

    @RequestMapping("deleteById")
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Integer id) throws Exception {
        try {
            // 删除该部门
            deptMapper.deleteById(id);

            if (true){
                throw new Exception("发生了错误");
            }

            // 删除部门对应部门ID的员工
            empMapper.deleteByDeptId(id);
        }finally {
            // 记录删除部门日志
            DeptLog deptLog = new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());
            deptLog.setDescription("删除了ID" + id + "的部门");

            deptLogService.insertDeptLog(deptLog);
        }
    }

(删除ID为2的部门)

SpringBoot项目的事务实现_第6张图片

(删除部门失败,不影响添加日志)

SpringBoot项目的事务实现_第7张图片

SpringBoot项目的事务实现_第8张图片

需要注意的是,事务传播属性是加在需要设置的方法上(添加日志方法),而不是调用方法上(删除部门方法)

你可能感兴趣的:(spring,boot,java,后端)