SpringBoot - 事务处理

事务介绍

是一组操作的集合,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败

Spring 事务管理:

  • 注解: @Transactional
  • 位置:业务层的方法上、类上、接口上
  • 作用:将当前方法交给spring 进行事务管理,方法执行前,开始事务。成功执行完毕,提交事务,出现异常,回滚事务

引入案例

package com.chuangzhou.serivce.impl;

import com.chuangzhou.mapper.DeptMapper;
import com.chuangzhou.mapper.EmpMapper;
import com.chuangzhou.pojo.Dept;
import com.chuangzhou.pojo.Emp;
import com.chuangzhou.serivce.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private EmpMapper empMapper;

    //删除部门信息
    @Transactional
    @Override
    public void delete(Integer id) {

        deptMapper.deleteById(id); // 删除部门

        int i = 1/ 0;  //遇到异常后,部门被删除,但是部门下的员工无法删除

        empMapper.deleteByDeptId(id);
    }
}

application.yml打开日志:

logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager: debug

执行删除部门后可以看到事务回滚日志:

事务进阶 - rollbackFor

    @Transactional
    @Override
    public void delete(Integer id) throws Exception {

        deptMapper.deleteById(id); // 删除部门

        if(true){
            throw new Exception("出错了......");
        }

        empMapper.deleteByDeptId(id);

    }

执行以上代码后会发现事务没有回滚,部门被删除了,但是部门下的员工却没有被删除。

原因:

@Trancaction注解:默认情况下只有出现RunTimeException 才回滚异常。

解决:

rollbackFor属性用于控制出现何种异常类型,回滚事务

    @Transactional(rollbackFor = {Exception.class}) //所有的异常都会回滚
    @Override
    public void delete(Integer id) throws Exception {

        deptMapper.deleteById(id); // 删除部门

        if(true){
            throw new Exception("出错了......");
        }

        empMapper.deleteByDeptId(id);

    }

成功回滚:

事务进阶 - propagation

背景:

  • 事务的传播行为:指的就时当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制

需求:删除员工时不管删除成功还是失败都将日志信息记录到数据库

引入案例:

deptServiceImpl 逻辑:

    @Transactional
    @Override
    public void delete(Integer id) throws Exception {

        try {
            deptMapper.deleteById(id); // 删除部门
            int i = 1/0;
            empMapper.deleteByDeptId(id);
        } finally {
            // 不管删除部门信息的操作是否成功 都需要将日志信息记录到数据库
            DeptLog deptLog = new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());
            deptLog.setDescription("执行了删除部门操作");
            deptLogService.insert(deptLog);
        }

    }

DeptLogImpl : 注意的是insert 方法也加入了 事务管理

package com.chuangzhou.serivce.impl;

import com.chuangzhou.mapper.DeptLogMapper;
import com.chuangzhou.pojo.DeptLog;
import com.chuangzhou.serivce.DeptLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class DeptLogImpl  implements DeptLogService {

    @Autowired
    private DeptLogMapper deptLogMapper;

    @Transactional
    @Override
    public void insert(DeptLog deptLog) {
        deptLogMapper.insert(deptLog);
    }
}

删除部分后发现日志信息并没有插入到数据库:

原因:
@Transaction 默认的传播行为:REQUIRE:有事务则加入,无事务创建新的事物

解决:

修改事务的默认值: @Transactional(propagation = Propagation.REQUIRES_NEW)

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

数据库也插入成功:

事务传播行为的可选值:

场景:

  • REQUIRED:大部分情况下都是用该传播行为即可。
  • REQUIRES_NEW: 当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功
posted @ 2023-08-27 10:36  chuangzhou  阅读(80)  评论(0编辑  收藏  举报