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

事务管理:确保数据一致性与业务完整性

摘要:本文围绕事务管理展开,先回顾事务基本概念与操作,后深入探讨Spring事务管理。通过具体案例剖析事务管理在实际应用中的问题及解决方案,详细介绍@Transactional注解及其属性rollbackForpropagation的使用。

关键词:事务管理;Spring框架;@Transactional注解;事务传播行为

参考资料:黑马程序员day13 完整项目请从第10天开始看

一、事务管理概述

1.1 事务回顾

事务是一组不可分割的操作集合,作为一个整体向数据库提交或撤销请求,确保这组操作要么全部成功,要么全部失败。其具体操作包含以下三步:

  1. 开启事务:在一组操作开始前执行,指令为start transaction / begin
  2. 提交事务:当所有操作成功完成后,使用commit指令提交。
  3. 回滚事务:若操作过程中出现异常,通过rollback指令回滚事务。

1.2 Spring事务管理

1.2.1 案例

以解散部门为例,需求是删除部门信息的同时删除该部门下的所有员工数据。

  1. 代码实现

DeptServiceImpl

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;//根据部门id,删除部门信息及部门下的所有员工@Overridepublic void delete(Integer id) {//根据部门id删除部门信息deptMapper.deleteById(id);//删除部门下的所有员工信息empMapper.deleteByDeptId(id);}
}

DeptMapper

@Mapper
public interface DeptMapper {/*** 根据id删除部门信息* @param id   部门id*/@Delete("delete from dept where id = #{id}")void deleteById(Integer id);
}

EmpMapper

@Mapper
public interface EmpMapper {//根据部门id删除部门下所有员工@Delete("delete from emp where dept_id=#{deptId}")public int deleteByDeptId(Integer deptId);
}
  1. 测试情况:正常运行时,dept表和emp表中的相关数据均被删除。但当在DeptServiceImpldelete方法中添加异常模拟代码(如int i = 1/0;)后,部门信息被删除,而部门下的员工数据未删除,导致数据不一致。
1.2.2 原因分析

上述问题产生的原因在于,删除部门操作先执行且成功,随后的异常导致后续删除员工数据的操作未执行。要保证数据一致性,需确保解散部门的两个业务操作要么同时成功,要么同时失败,这可通过事务来实现。在Spring框架中,可借助@Transactional注解简化事务控制代码。

1.2.3 @Transactional注解

@Transactional注解用于控制事务,在方法执行前开启事务,执行完毕后提交事务,若执行过程中出现异常则回滚事务。通常在业务层使用(spring的三层业务结构是:表现层cotroller、业务逻辑层service、数据访问层Dao),因为业务层的一个业务功能可能涉及多个数据访问操作,通过在业务层控制事务,可将这些操作纳入同一事务范围。

@Transactional注解可置于方法、类或接口上:

  • 方法:仅当前方法由Spring进行事务管理。
  • :当前类中的所有方法都由Spring管理事务。
  • 接口:接口下所有实现类的所有方法均由Spring管理事务。

DeptServiceImpldelete方法上添加@Transactional注解后,再次测试,由于异常事务回滚,部门和员工数据均未被删除,保证了数据一致性。同时,可在application.yml配置文件中开启事务管理日志,以便查看事务相关信息:

#spring事务管理日志
logging:level:org.springframework.jdbc.support.JdbcTransactionManager: debug

1.3 事务进阶

1.3.1 rollbackFor

在业务方法上添加@Transactional注解实现事务管理时,默认情况下,只有RuntimeException(运行时异常)会触发事务回滚。

例如:

  • 当业务方法中抛出除0的算数运算异常(运行时异常)时,事务会回滚。
  • 但当抛出Exception(编译时异常)时,事务不会回滚。

若希望所有异常都能触发事务回滚,可通过配置@Transactional注解的rollbackFor属性指定异常类型。如:

@Slf4j
@Service
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;@Override@Transactional(rollbackFor = Exception.class)public void delete(Integer id) {//根据部门id删除部门信息deptMapper.deleteById(id);//模拟:异常发生int num = id / 0;//删除部门下的所有员工信息empMapper.deleteByDeptId(id);}
}

重新启动服务测试删除部门操作,可发现由于异常事务回滚,部门未被删除。由此可见,在Spring事务管理中,默认仅运行时异常会回滚事务,若要回滚指定类型异常,可通过rollbackFor属性指定。

PS:rollbackFor参数用来指定哪些异常会触发事务回滚。 rollbackFor = Exception.class 表明所有 Exception 类型的异常都会触发回滚,这其中包含了受检查异常(Checked Exception)。

1.3.3 propagation
1.3.3.1 介绍

propagation属性用于配置事务的传播行为,即当一个事务方法调用另一个事务方法时,后者应如何进行事务控制。例如,有AB两个事务方法,均添加@Transactional注解,若A方法调用B方法,事务传播行为决定B方法是加入A方法的事务,还是新建一个事务。

通过在@Transactional注解后指定propagation属性来控制事务传播行为,常见的事务传播行为如下:

属性值含义
REQUIRED【默认值】需要事务,有则加入,无则创建新事务
REQUIRES_NEW需要新事务,无论有无,总是创建新事务
SUPPORTS支持事务,有则加入,无则在无事务状态中运行
NOT_SUPPORTED不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务
MANDATORY必须有事务,否则抛异常
NEVER必须没事务,否则抛异常

实际应用中,重点关注REQUIRED(默认值)和REQUIRES_NEW

1.3.3.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 '部门操作日志表';

引入实体类DeptLogMapper接口DeptLogMapper、业务接口DeptLogService及业务实现类DeptLogServiceImpl

  1. 代码实现
@Slf4j
@Service
//@Transactional //当前业务实现类中的所有的方法,都添加了spring事务管理机制
public class DeptServiceImpl implements DeptService {@Autowiredprivate DeptMapper deptMapper;@Autowiredprivate EmpMapper empMapper;@Autowiredprivate 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);}}//省略其他代码...
}
  1. 测试与分析
    • 测试情况:重新启动SpringBoot服务,测试删除3号部门,程序发生Exception异常,执行事务回滚,dept_log表中未记录日志数据。
    • 原因分析delete操作开启一个事务,insert操作默认事务传播行为为REQUIRED,即加入delete操作的事务。由于同一事务中的操作要么同时成功,要么同时失败,异常发生时事务回滚,导致insert操作也被回滚。
  2. 解决方案
    DeptLogServiceImpl类的insert方法上添加@Transactional(propagation = Propagation.REQUIRES_NEW)表示无论是否存在事务,都创建新事务并独立运行。 重启服务再次测试删除3号部门,insert方法运行完毕后事务立即提交,即使外部delete方法所在事务出现异常,已提交的insert事务也不会回滚。

相关文章:

  • celery rabbitmq 配置 broker和backend
  • 【充电器的原理】
  • CS5346 - Improving and Evaluating Effectiveness of Visualizations(提高和评估可视化的效果)
  • 云函数采集架构:Serverless模式下的动态IP与冷启动优化
  • 栅格数据处理
  • 技术速递|使用 BrowserStack App Automate 和 Appium UI 测试 .NET MAUI 应用
  • BladeX单点登录与若依框架集成实现
  • C++项目-衡码云判项目演示
  • LNMP架构部署论坛
  • 基础学习:(6)nanoGPT
  • [U-Net]CA-Net
  • FreeRTOS四种信号量详解
  • Docker私有仓库页面访问实现
  • Python----机器学习(基于PyTorch框架的逻辑回归)
  • 代码随想录算法训练营第十九天
  • 【Python进阶】字符串操作全解与高效应用
  • LTSPICE仿真电路:(二十七)三极管伏安特性曲线仿真
  • 未启用CUDA支持的PyTorch环境** 中使用GPU加速解决方案
  • 时序数据预测:TDengine 与机器学习框架的结合(一)
  • 微信小程序数字滚动效果
  • 手机网站设置在哪里找/南京seo域名
  • thinkphp 企业网站/网上广告怎么推广
  • 宿迁房产交易中心官网/免费seo工具大全
  • wordpress 美拍插件/seo发包软件
  • 毕业设计做网站答辩/制作链接的app的软件
  • 网站301定向/一元友情链接平台