Javaweb之SpringBootWeb案例之propagation属性案例演示的详细解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
日志服务 SLS,月写入数据量 50GB 1个月
全局流量管理 GTM,标准版 1个月
简介: Javaweb之SpringBootWeb案例之propagation属性案例演示的详细解析
案例

接下来我们就通过一个案例来演示下事务传播行为propagation属性的使用。

需求:解散部门时需要记录操作日志

由于解散部门是一个非常重要而且非常危险的操作,所以在业务当中要求每一次执行解散部门的操作都需要留下痕迹,就是要记录操作日志。而且还要求无论是执行成功了还是执行失败了,都需要留下痕迹。

步骤:

  1. 执行解散部门的业务:先删除部门,再删除部门下的员工(前面已实现)
  2. 记录解散部门的日志,到日志表(未实现)

准备工作:

  1. 创建数据库表 dept_log 日志表:
create table dept_log(
    id int auto_increment comment '主键ID' primary key,
    create_time datetime null comment '操作时间',
    description varchar(300) null comment '操作描述'
)comment '部门操作日志表';
  1. 引入资料中提供的实体类:DeptLog
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptLog {
    private Integer id;
    private LocalDateTime createTime;
    private String description;
}
  1. 引入资料中提供的Mapper接口:DeptLogMapper
@Mapper
public interface DeptLogMapper {
    @Insert("insert into dept_log(create_time,description) values(#{createTime},#{description})")
    void insert(DeptLog log);
}
  1. 引入资料中提供的业务接口:DeptLogService
public interface DeptLogService {
    void insert(DeptLog deptLog);
}
  1. 引入资料中提供的业务实现类:DeptLogServiceImpl
@Service
public class DeptLogServiceImpl implements DeptLogService {
    @Autowired
    private DeptLogMapper deptLogMapper;
    @Transactional //事务传播行为:有事务就加入、没有事务就新建事务
    @Override
    public void insert(DeptLog deptLog) {
        deptLogMapper.insert(deptLog);
    }
}

代码实现:

业务实现类:DeptServiceImpl

@Slf4j
@Service
//@Transactional //当前业务实现类中的所有的方法,都添加了spring事务管理机制
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    
    @Autowired
    private EmpMapper empMapper;
    @Autowired
    private DeptLogService deptLogService;
    //根据部门id,删除部门信息及部门下的所有员工
    @Override
    @Log
    @Transactional(rollbackFor = Exception.class) 
    public void delete(Integer id) throws Exception {
        try {
            //根据部门id删除部门信息
            deptMapper.deleteById(id);
            //模拟:异常
            if(true){
                throw new Exception("出现异常了~~~");
            }
            //删除部门下的所有员工信息
            empMapper.deleteByDeptId(id);
        }finally {
            //不论是否有异常,最终都要执行的代码:记录日志
            DeptLog deptLog = new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());
            deptLog.setDescription("执行了解散部门的操作,此时解散的是"+id+"号部门");
            //调用其他业务类中的方法
            deptLogService.insert(deptLog);
        }
    }
    
    //省略其他代码...
}

测试:

重新启动SpringBoot服务,测试删除3号部门后会发生什么?

  • 执行了删除3号部门操作
  • 执行了插入部门日志操作
  • 程序发生Exception异常
  • 执行事务回滚(删除、插入操作因为在一个事务范围内,两个操作都会被回滚)

然后在dept_log表中没有记录日志数据

原因分析:

接下来我们就需要来分析一下具体是什么原因导致的日志没有成功的记录。

  • 在执行delete操作时开启了一个事务
  • 当执行insert操作时,insert设置的事务传播行是默认值REQUIRED,表示有事务就加入,没有则新建事务
  • 此时:delete和insert操作使用了同一个事务,同一个事务中的多个操作,要么同时成功,要么同时失败,所以当异常发生时进行事务回滚,就会回滚delete和insert操作

解决方案:

在DeptLogServiceImpl类中insert方法上,添加@Transactional(propagation = Propagation.REQUIRES_NEW)

Propagation.REQUIRES_NEW :不论是否有事务,都创建新事务 ,运行在一个独立的事务中。

@Service
public class DeptLogServiceImpl implements DeptLogService {
    @Autowired
    private DeptLogMapper deptLogMapper;
    @Transactional(propagation = Propagation.REQUIRES_NEW)//事务传播行为:不论是否有事务,都新建事务
    @Override
    public void insert(DeptLog deptLog) {
        deptLogMapper.insert(deptLog);
    }
}

重启SpringBoot服务,再次测试删除3号部门:

那此时,DeptServiceImpl中的delete方法运行时,会开启一个事务。 当调用 deptLogService.insert(deptLog) 时,也会创建一个新的事务,那此时,当insert方法运行完毕之后,事务就已经提交了。 即使外部的事务出现异常,内部已经提交的事务,也不会回滚了,因为是两个独立的事务。

到此事务传播行为已演示完成,事务的传播行为我们只需要掌握两个:REQUIRED、REQUIRES_NEW。

  • REQUIRED :大部分情况下都是用该传播行为即可。
  • REQUIRES_NEW :当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。


相关文章
|
1月前
|
数据采集 人工智能 安全
数据治理的实践与挑战:大型案例解析
在当今数字化时代,数据已成为企业运营和决策的核心资源。然而,随着数据量的爆炸性增长和数据来源的多样化,数据治理成为了企业面临的重要挑战之一。本文将通过几个大型案例,探讨数据治理的实践、成效以及面临的挑战。
数据治理的实践与挑战:大型案例解析
|
8天前
|
存储 人工智能 自然语言处理
高效档案管理案例介绍:文档内容批量结构化解决方案解析
档案文件内容丰富多样,传统人工管理耗时低效。思通数科AI平台通过自动布局分析、段落与标题检测、表格结构识别、嵌套内容还原及元数据生成等功能,实现档案的高精度分块处理和结构化存储,大幅提升管理和检索效率。某历史档案馆通过该平台完成了500万页档案的数字化,信息检索效率提升60%。
|
18天前
|
Prometheus 监控 Cloud Native
实战经验:成功的DevOps实施案例解析
实战经验:成功的DevOps实施案例解析
33 6
|
21天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
14 1
|
1月前
|
数据格式
常用的Lambda表达式案例解析,工作中都会用到!
常用的Lambda表达式案例解析,工作中都会用到!
|
1月前
|
移动开发 JavaScript 前端开发
Javaweb之Vue路由的详细解析
Vue.js是一款备受欢迎的前端框架,以其简洁的API和组件化开发模式著称。Vue Router作为其官方路由管理器,在构建单页面应用(SPA)时发挥关键作用,通过URL变化管理组件切换,实现无刷新过渡。本文将详细介绍Vue Router的基础概念、主要功能及使用步骤,帮助JavaWeb开发者快速掌握其工作原理及实践应用。
14 1
|
1月前
|
存储 数据采集 监控
CDGA\如何建立实现数据治理的效率价值框架:实践案例解析
数据治理是一个持续优化的过程。组织应建立健全的监督与评估机制,定期对数据治理工作进行评估,发现问题及时整改。广东药科大学通过数据全景图和数据监控大屏,实现了对数据治理成果的动态、多维度呈现与监控,为科学管理决策提供了有力支撑。
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
66 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
52 0
|
1月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
59 0

推荐镜像

更多