当前位置: 首页 > article >正文

事务管理-03.事务进阶-propagation属性

一.工具

在介绍事务的propagation属性前,我们首先介绍一个工具:Grep Console,该工具用来实现将idea输出出的日志信息进行选择性的高亮展示。

当要选择日志中的某一部分高亮展示时,只需要右键点击Add Highlight即可。此时日志中所有的该部分都会变为高亮。

 

二.propagation属性

propagation属性是用来控制事务的传播行为的。所谓事务的传播行为,就是指当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。例如a()方法是一个事务,在a()方法中又调用了b()方法,b()方法又是一个事务,那么这两个事务是共用一个事务,还是b()再重新开启一个新事务呢?

有以下几种传播行为属性值

我们重点关注前两个:

REQUIRED:【默认值】需要事务,有则加入,无则创建新事务

REQUIRES_NEW:需要新事务,无论有无,总是创建新事务

我们还是通过一个案例来引入propagation属性值。

我们需要定义以下内容:

1.pojo包下定义实体类DeptLog.java

package com.gjw.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeptLog {private Integer id;private LocalDateTime createTime;private String description;
}

2.service层定义接口DeptLogService和实现类DeptLogServiceImpl.java

接口DeptLogService

package com.gjw.service;import com.gjw.pojo.DeptLog;public interface DeptLogService {void insert(DeptLog deptLog);
}

实现类DeptLogServiceImpl.java,该类中的insert()方法也是一个事务。

package com.gjw.service.impl;import com.gjw.mapper.DeptLogMapper;
import com.gjw.pojo.DeptLog;
import com.gjw.service.DeptLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class DeptLogServiceImpl implements DeptLogService {@Autowiredprivate DeptLogMapper deptLogMapper;@Transactional@Overridepublic void insert(DeptLog deptLog) {deptLogMapper.insert(deptLog);}
}

3.DeptLogMapper接口:操作数据库,将日志内容记录在数据库表中

package com.gjw.mapper;import com.gjw.pojo.DeptLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface DeptLogMapper {@Insert("insert into dept_log(create_time, description) VALUES (#{createTime},#{description})")void insert(DeptLog deptLog);
}

定义完成后,我们在DeptServiceImpl.java中的deleteById方法中调用操作日志的代码逻辑。因为解散部门时,不管成功还是失败,都要记录操作日志,因此要将日志操作存放在finally代码块中。我们使用try/finally来组合代码。在try中执行删除部门及相关员工的操作,在finally中执行日志操作。

package com.gjw.service.impl;import com.gjw.mapper.DeptLogMapper;
import com.gjw.mapper.DeptMapper;
import com.gjw.mapper.EmpMapper;
import com.gjw.pojo.Dept;
import com.gjw.pojo.DeptLog;
import com.gjw.service.DeptLogService;
import com.gjw.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.time.LocalDateTime;
import java.util.List;@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;@Autowiredprivate DeptLogService deptLogService;@Overridepublic List<Dept> list() {return deptMapper.list();}//    @Transactional(rollbackFor = Exception.class)      // spring事务管理   方法开始执行之前开启事务,方法执行完毕之后提交事务,方法运行过程中出现异常会回滚事务   rollbackFor:定义异常出现后回滚的类型,Exception.class表示不论出现任何异常均回滚事务,而默认只出现运行时异常才回滚事务@Transactional@Overridepublic void deleteById(Integer id) throws Exception {// 根据部门id删除部门,同时也要删除部门下的员工try {deptMapper.deleteById(id);int a = 1/0;empMapper.deleteByDeptId(id);} finally {DeptLog deptLog = new DeptLog();deptLog.setCreateTime(LocalDateTime.now());deptLog.setDescription("删除id为"+id+"的部门");deptLogService.insert(deptLog);}}@Overridepublic void add(Dept dept) {dept.setCreateTime(LocalDateTime.now());dept.setUpdateTime(LocalDateTime.now());deptMapper.insert(dept);}@Overridepublic Dept getById(Integer id) {return deptMapper.getById(id);}@Overridepublic void update(Dept dept) {dept.setUpdateTime(LocalDateTime.now());deptMapper.update(dept);    }
}

接下来我们启动服务来执行删除部门的操作。此时因为1/0会导致运行时错误被捕捉到。接着我们刷新表结构,发现表结构中没有任何数据。该日志并没有被记录。这与我们的要求:“不论成功还是失败,都要记录操作日志”这一要求相违背,这是为什么呢?

我们来看一下控制台中输出的日志:

当前代码中的deleteById代码块执行时,作为一个事务,会首先执行删除部门的操作,接着遇到异常,删除部门下的员工这一代码将不会执行。但是finally中的代码块将会执行。而finally中的代码块中的insert操作也是一个事务,这就涉及到了两个事务之间的调用,也就是传播行为的问题了。在控制台日志当中输出:

Participating in existing transaction,也就是说参与到了现存的事务当中了。也就是说:insert这个后执行的事务参与到了deleteById这个先执行的事务当中了。也就是说deleteById和insert共用一个事务。然后便执行insert语句成功插入一条记录,但是由于出现了除以零的异常,

因此deleteById事务要回滚,又因为共用一个事务,因此insert也跟着回滚了,这就导致了在数据库中没有任何日志记录。

这是因为我们没有配置propagation属性,那么默认就是REQUIRED,需要事务,有则加入,无则创建新事务。

三.如何解决?

既然要解决这个问题,很明显的方法就是将这两个事务分开,使得不管deleteById()事务执行成功与否,insert()事务都将执行。那么就要使得insert()事务在执行时另开一个新的事务,而不管原来的事务是否存在。我们就要在insert()方法的@Transactional注解中加入propagation属性并指定属性值为REQUIRES_NEW。

package com.gjw.service.impl;import com.gjw.mapper.DeptLogMapper;
import com.gjw.pojo.DeptLog;
import com.gjw.service.DeptLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class DeptLogServiceImpl implements DeptLogService {@Autowiredprivate DeptLogMapper deptLogMapper;@Transactional(propagation = Propagation.REQUIRES_NEW)@Overridepublic void insert(DeptLog deptLog) {deptLogMapper.insert(deptLog);}
}

接着我们再次执行,捕获到异常后我们查看控制台输出:

可以看到挂起了当前事务,然后又创建了一个新的事务。

然后做了事务提交,这是提交了insert()方法的事务。

然后在内部的事务完成后再继续执行挂起的事务。

又因为外部的事务出现了异常,因此事务回滚。

 这样就将操作记录了下来。

四.总结

相关文章:

事务管理-03.事务进阶-propagation属性

一.工具 在介绍事务的propagation属性前&#xff0c;我们首先介绍一个工具&#xff1a;Grep Console&#xff0c;该工具用来实现将idea输出出的日志信息进行选择性的高亮展示。 当要选择日志中的某一部分高亮展示时&#xff0c;只需要右键点击Add Highlight即可。此时日志中所…...

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数&#xff1a;#paper/⭐⭐#​ 贡献&#xff1a; 我们研究了在更复杂的数据结构上预训练LM的问题&#xff0c;即&#xff0c;TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…...

模型疑问图像、嵌入、推理类型与说明

在进行模型使用的时候,有时候会碰到模型存在模型类型需要选择的情况,如下面deepseek模型选择模型类型图像、嵌入、推理。 以下是针对此问题的了解与说明: DeepSeek 模型是一个多模态人工智能模型,能够同时处理图像和文本数据,并在多种任务中实现高效的嵌入表示和推理。以下…...

WiFi IEEE 802.11协议精读:IEEE 802.11-2007,6,MAC service definition MAC服务定义

继续精读IEEE 802.11-2007 6&#xff0c;MAC service definition MAC服务定义 6.1 MAC服务概述 6.1.1 数据服务 此服务为对等逻辑链路控制&#xff08;LLC&#xff09;实体提供交换MAC服务数据单元&#xff08;MSDU&#xff09;的能力。为支持此服务&#xff0c;本地媒体访…...

Visual Studio Code 跨平台安装与配置指南(附官方下载链接)

一、软件定位与核心功能 Visual Studio Code&#xff08;简称VS Code&#xff09;是微软开发的开源跨平台代码编辑器&#xff0c;支持超过50种编程语言的智能补全、调试和版本控制功能。2025版本新增AI辅助编程模块&#xff0c;可自动生成单元测试代码和API文档注释。 二、下载…...

deepseek自动化代码生成

使用流程 效果第一步&#xff1a;注册生成各种大模型的API第二步&#xff1a;注册成功后生成API第三步&#xff1a;下载vscode在vscode中下载agent&#xff0c;这里推荐使用cline 第四步&#xff1a;安装完成后&#xff0c;设置模型信息第一步选择API provider&#xff1a; Ope…...

RK3568开发笔记-AD7616调试笔记

目录 前言 一、AD7616介绍 高分辨率 高速采样速率 宽模拟输入范围 集成丰富功能 二、原理图连接 三、设备树配置 四、内核驱动配置 五、AD芯片测试 总结 前言 在嵌入式数据采集领域,将模拟信号精准转换为数字信号至关重要。AD7616 作为一款性能卓越的 16 位模数转换器…...

【DeepSeek开源:会带来多大的影响】

DeepSeek 开源&#xff0c;震撼登场对云计算行业的冲击 巨头云厂商的新机遇 DeepSeek 开源后&#xff0c;为云计算行业带来了巨大的变革&#xff0c;尤其是为巨头云厂商创造了新的发展机遇。以阿里云为例&#xff0c;它作为云计算行业的领军者&#xff0c;与 DeepSeek 的合作…...

transformer架构嵌入层位置编码之动态NTK-aware位置编码

前文,我们已经构建了一个小型的字符级语言模型,是在transformer架构基础上实现的最基本的模型,我们肯定是希望对该模型进行改进和完善的。所以我们的另外一篇文章也从数据预处理、模型架构、训练策略、评估方法、代码结构、错误处理、性能优化等多个方面提出具体的改进点,但…...

OceanBase + DeepSeek:5分钟免费搭建企业知识库

过去一个月&#xff0c;DeepSeek 在全球范围内引发了热烈讨论。其突破性的 AI 能力使其日流量显著超越 Claude 和 Perplexity&#xff0c;吸引了众多企业和技术专家的高度关注。随着 AI 技术的不断进步&#xff0c;企业正面临一场深刻的智能化变革——如何通过 AI 重构业务&…...

水利工程安全包括哪几个方面

水利工程安全培训的内容主要包括以下几个方面&#xff1a; 基础知识和技能培训 &#xff1a; 法律法规 &#xff1a;学习水利工程相关的安全生产法律法规&#xff0c;了解安全生产标准及规范。 事故案例 &#xff1a;通过分析事故案例&#xff0c;了解事故原因和教训&#x…...

基于 sklearn 的均值偏移聚类算法的应用

基于 sklearn 的均值偏移聚类算法的应用 在机器学习和数据挖掘中&#xff0c;聚类算法是一类非常重要的无监督学习方法。它的目的是将数据集中的数据点划分为若干个类&#xff0c;使得同一类的样本点彼此相似&#xff0c;而不同类的样本点相互之间差异较大。均值偏移聚类&…...

C/C++语言知识点二

1. 编程算法之“哨兵”思想 哨兵思想是一种编程技巧&#xff0c;通过在数据结构的边界或特定位置放置一个特殊值&#xff08;称为“哨兵”&#xff09;&#xff0c;来简化逻辑判断和提高代码效率。哨兵通常是一个标记值&#xff0c;用于指示某种条件或边界&#xff0c;从而避免…...

国产OS上完整编译Qt5.15、搭建基本开发环境需要的库

近期有师弟问我国产OS安装Qt5.15编译老是不完整&#xff0c;不是没声音&#xff0c;就是没视频&#xff0c;或者没有xcb。通过QEMU模拟Arm64&#xff0c;闲来20几天摸索&#xff0c;完整编译了Qt5.15&#xff0c;并编译成功了我的SDR玩具taskBus。 1.主要结论&#xff1a; 该O…...

Python 编程题第一节:判断素数、求阶乘、求圆的周长和面积、求三角形斜边长、比较三个数的大小、找出区间内的素数

判断素数 挺简单的&#xff0c;设一个flag来判断是否是素数&#xff0c;从2开始到前一个数&#xff0c;可以整除便不是素数&#xff0c;1不是素数 aint(input()) flagFalse for i in range(2,a):if a%i0:flagTruebreak if flagTrue or a1:print("不是素数") else:p…...

Python批量压缩并上载CSV数据文件到Box企业云盘

Python在Windows下批量压缩CSV文件为ZIP并异步上传到Box企业云&#xff0c;需整合文件处理、异步任务、配置管理和日志记录功能。 该方案通过线程池实现异步上传&#xff0c;每个文件独立压缩处理&#xff0c;异常发生时继续后续任务。日志系统记录完整操作流水&#xff0c;配置…...

MyBatis简明教程

MyBatis 是一个用于简化数据库操作的持久层框架&#xff0c;它的核心思想是 将 SQL 与 Java 代码解耦&#xff0c;让开发者专注于 SQL 的编写&#xff0c;同时自动处理重复的数据库操作步骤。 一、核心思想&#xff1a;SQL 与 Java 解耦 传统 JDBC 需要开发者手动管理数据库连…...

有什么区别?Elastic 和 Splunk 数据层

作者&#xff1a;来自 Elastic Ugo Sangiorgi, Matt Wehle 了解 Elastic 和 Splunk 数据管理方法之间的主要区别&#xff0c;以便做出明智的决策&#xff0c;实现高效的数据处理 在数据管理领域&#xff0c;在讨论如何根据不同的性能要求提供和/或保留数据时&#xff0c;经常会…...

Tips :仿真竞争条件 指的是什么?

文章目录 **为什么会出现仿真竞争条件?****典型场景举例****System Verilog 如何解决竞争条件?****1. 使用 `program` 块隔离测试平台****2. 使用 `clocking` 块明确时序关系****3. 非阻塞赋值(`<=`)的合理使用****竞争条件的根本原因****总结****代码结构****1. 设计模…...

BGP状态和机制

BGP邻居优化 为了增加稳定性,通常建议实验回环口来建立邻居。更新源:建立邻居和邻居所学习到的路由的下一跳。多跳:EBGP邻居建立默认选哟直连,因为TTL=1,如果非直连,必须修改TTL。命令备注peer 2.2.2.2 connect-interface lo1配置更新源peer 2.2.2.2 ebgp-max-hop 2配置T…...

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源

【电机控制器】PY32F00BF15U6TR-从KEIL5中计算资源消耗资源 文章目录 [TOC](文章目录) 前言一、MCU芯片手册二、实验三、实验结论四、参考资料总结 前言 使用工具&#xff1a; 1.KEIL5编译器 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、MCU芯片…...

CaffeineCache自定义缓存时间

文章目录 1、POM文件依赖2、声明缓存3、缓存使用4、测试缓存5、自定义缓存过期时间6、测试自定义超时时间 1、POM文件依赖 <dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1…...

python实战项目58:采集蜻蜓FM热门音频top排行榜

python实战项目58:采集蜻蜓FM热门音频top排行榜 一、采集流程介绍二、数据接口采集三、使用xpath提取页面数据1、抓包,找到数据接口2、发送请求,获取数据3、提取数据4、保存数据一、采集流程介绍 蜻蜓FM热门音频top排行榜的链接为: https://m.qingting.fm/rank/,首页如下图…...

STM32【3】芯片的底层组成概论

关于单片机的组成 单片机的意思是&#xff0c;小小计算电脑&#xff0c;麻雀虽小&#xff0c;五脏俱全&#xff0c;里面包含了CPU&#xff0c;ROM&#xff0c;RAM&#xff0c;各种外设。 CPU地位最高&#xff0c;可以访问ROM和RAM&#xff0c;Flash&#xff0c;GPIO等外设&…...

基于django图书信息管理系统的搭建(增删改查)

✍django项目搭建教程 ☞ ----------------- 教程 本文主要讲解django如何连接数据库MySQL并且可视化展示&#xff0c;实现增删改查功能 目录 一. 创建django应用 二. 数据库配置 三. 查看数据库 四. 编写代码 4.1视图函数 4.2 配置URL 4.3创建模板文件 4.…...

Kotlin 知识点二 延迟初始化和密封类

对变量延迟初始化 Kotlin 语言的许多特性&#xff0c;包括变量不可变&#xff0c;变量不可为空&#xff0c;等等。这些特性 都是为了尽可能地保证程序安全而设计的&#xff0c;但是有些时候这些特性也会在编码时给我们带来不 少的麻烦。 比如&#xff0c;如果你的类中存在很多…...

基于SpringBoot的“古城景区管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“古城景区管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 系统首页界面 系统注册界面 景…...

QT C++ QtConcurrent::run 异步任务 简单例子

QtConcurrent命名空间提供了高级API&#xff0c;使得无需使用低级线程原语即可编写多线程程序。 ‌QtConcurrent::run‌是Qt框架中用于简化并发编程的一个功能&#xff0c;主要用于在后台线程中异步执行函数或成员函数。其主要用途包括&#xff1a; ‌异步执行函数‌&#xf…...

力扣hot100 —— 电话号码字母组合; 子集 (非回溯做法)简单易懂

由于博主对回溯也不是很熟悉&#xff0c;这里提出一种简单易懂的解法&#xff08;有点暴力&#xff09; 解题思路&#xff1a; 每个数字对应有自己的字母串&#xff1b; 首先遍历将每个字母存入也就是 res{{a},{b},{c}} 然后遍历后续数子对应的字母&#xff0c;让每个字母与…...

企业业务安全进阶之路:AI技术与数据分析的应用

在数字化时代&#xff0c;企业业务安全面临着前所未有的挑战。从网络安全到数据保护&#xff0c;每一个环节都至关重要。本文将探讨如何通过AI技术和数据分析来提升企业业务安全防护能力&#xff0c;确保企业在不断变化的安全威胁面前保持领先地位。 企业业务安全的重要性 企…...