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

Spring事务传播行为-实践向

前言

Spring事务传播行为定义了多个事务方法相互调用时,事务应该如何传播的规则。它是Spring事务管理的核心概念之一,决定了事务的边界范围。Spring事务传播行为总共有七种,如果没有理解的话很容易忘记,本文希望以实践验证的方式带大家了解常用的传播行为。

初始数据状态

下文会进行一系列验证,分别修改员工和资产表,此处记录初始状态,每轮测试如果成功修改了,下轮测试会手动重置成如下状态:
t_emp
t_emp
t_asset_info
t_asset_info

1、REQUIRED传播行为

REQUIRED:必须的,会将多个嵌套的事务合并成一个事务管理,能够保证多个事务同时成功或同时失败,为最常用的传播行为,适用于90%以上的场景。

1-1、演示使用REQUIRED传播行为,在外部事务中抛出异常

先更新员工信息,然后更新资产信息,在员工信息更新commit之前抛出自定义异常。

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate AssetInfoServiceImpl assetInfoService;@Override@Transactionalpublic void updateEmpInfo() throws IOException {empMapper.update(new UpdateWrapper<>(new Emp()).set("emp_salary", 114.58).set("emp_name", "一个名字").eq("emp_id", 111));assetInfoService.updateAssetInfo();int i = 1 / 0; // 故意抛出异常}
}@Service
public class AssetInfoServiceImpl extends ServiceImpl<AssetInfoMapper, AssetInfoDTO> implements IAssetInfoService {@Autowiredprivate AssetInfoMapper assetInfoMapper;@Override@Transactionalpublic void updateAssetInfo() throws IOException {assetInfoMapper.update(new UpdateWrapper<>(new AssetInfoDTO()).set("asset_status", 99).eq("asset_number", "5277dd895001bbbdb444f174db644d75"));}
}

测试后查看数据,两个事务都回滚了

t_emp
t_asset_info

1-2、演示使用REQUIRED传播行为,在内部事务中抛出异常

先更新员工信息,然后更新资产信息,在更新资产信息commit之前抛出自定义异常。

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate AssetInfoServiceImpl assetInfoService;@Override@Transactionalpublic void updateEmpInfo() throws IOException {empMapper.update(new UpdateWrapper<>(new Emp()).set("emp_salary", 114.58).set("emp_name", "一个名字").eq("emp_id", 111));assetInfoService.updateAssetInfo();}
}@Service
public class AssetInfoServiceImpl extends ServiceImpl<AssetInfoMapper, AssetInfoDTO> implements IAssetInfoService {@Autowiredprivate AssetInfoMapper assetInfoMapper;@Override@Transactionalpublic void updateAssetInfo() throws IOException {assetInfoMapper.update(new UpdateWrapper<>(new AssetInfoDTO()).set("asset_status", 99).eq("asset_number", "5277dd895001bbbdb444f174db644d75"));int i = 1 / 0; // 故意抛出异常}
}

测试后查看数据,两个事务都回滚了

t_emp
t_asset_info

2、REQUIRES_NEW传播行为

REQUIRES_NEW:需要新的 REQUIRES_NEW会从数据库拿一个独立的连接构成一个独立的事务,能够保证内外事务的独立性

2-1、演示使用REQUIRES_NEW传播行为,在外部事务中抛出异常

先更新员工信息,然后更新资产信息,在员工信息更新commit之前抛出自定义异常。
外部事务为REQUIRED传播行为,内部事务为REQUIRES_NEW传播行为

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate AssetInfoServiceImpl assetInfoService;@Override@Transactionalpublic void updateEmpInfo() throws IOException {empMapper.update(new UpdateWrapper<>(new Emp()).set("emp_salary", 114.58).set("emp_name", "一个名字").eq("emp_id", 111));assetInfoService.updateAssetInfo();int i = 1 / 0; // 故意抛出异常}
}@Service
public class AssetInfoServiceImpl extends ServiceImpl<AssetInfoMapper, AssetInfoDTO> implements IAssetInfoService {@Autowiredprivate AssetInfoMapper assetInfoMapper;@Override@Transactional(propagation = Propagation.REQUIRES_NEW)public void updateAssetInfo() throws IOException {assetInfoMapper.update(new UpdateWrapper<>(new AssetInfoDTO()).set("asset_status", 99).eq("asset_number", "5277dd895001bbbdb444f174db644d75"));}
}

测试后查看数据,外部事务回滚了,内部事务提交成功

t_emp
t_asset_info

2-2、演示使用REQUIRES_NEW传播行为,在内部事务中抛出异常【未手动捕获】

先更新员工信息,然后更新资产信息,在资产信息更新commit之前抛出自定义异常。
内部与外部事务均设置为REQUIRES_NEW传播行为

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate AssetInfoServiceImpl assetInfoService;@Override@Transactional(propagation = Propagation.REQUIRES_NEW)public void updateEmpInfo() throws IOException {empMapper.update(new UpdateWrapper<>(new Emp()).set("emp_salary", 114.58).set("emp_name", "一个名字").eq("emp_id", 111));assetInfoService.updateAssetInfo();}
}@Service
public class AssetInfoServiceImpl extends ServiceImpl<AssetInfoMapper, AssetInfoDTO> implements IAssetInfoService {@Autowiredprivate AssetInfoMapper assetInfoMapper;@Override@Transactional(propagation = Propagation.REQUIRES_NEW)public void updateAssetInfo() throws IOException {assetInfoMapper.update(new UpdateWrapper<>(new AssetInfoDTO()).set("asset_status", 99).eq("asset_number", "5277dd895001bbbdb444f174db644d75"));int i = 1 / 0; // 故意抛出异常}
}

测试后查看数据,两个事务都回滚了

t_emp
t_asset_info

2-3、演示使用REQUIRES_NEW传播行为,在内部事务中抛出异常【手动捕获】

先更新员工信息,然后更新资产信息,在资产信息更新commit之前抛出自定义异常。
内部与外部事务均设置为REQUIRES_NEW传播行为
手动捕获内部异常

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate AssetInfoServiceImpl assetInfoService;@Override@Transactional(propagation = Propagation.REQUIRES_NEW)public void updateEmpInfo() throws IOException {empMapper.update(new UpdateWrapper<>(new Emp()).set("emp_salary", 114.58).set("emp_name", "一个名字").eq("emp_id", 111));try {assetInfoService.updateAssetInfo();} catch (Exception e) {log.error("updateAssetInfo error", e);}}
}@Service
public class AssetInfoServiceImpl extends ServiceImpl<AssetInfoMapper, AssetInfoDTO> implements IAssetInfoService {@Autowiredprivate AssetInfoMapper assetInfoMapper;@Override@Transactional(propagation = Propagation.REQUIRES_NEW)public void updateAssetInfo() throws IOException {assetInfoMapper.update(new UpdateWrapper<>(new AssetInfoDTO()).set("asset_status", 99).eq("asset_number", "5277dd895001bbbdb444f174db644d75"));int i = 1 / 0; // 故意抛出异常}
}

测试后查看数据,外部事务正常提交,内部事务回滚了

t_emp
t_asset_info

3、NESTED传播行为

嵌套事务

3-1、演示使用NESTED传播行为,在内部事务中抛出异常【未手动捕获】

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate AssetInfoServiceImpl assetInfoService;@Override@Transactionalpublic void updateEmpInfo() throws IOException {empMapper.update(new UpdateWrapper<>(new Emp()).set("emp_salary", 114.58).set("emp_name", "一个名字").eq("emp_id", 111));assetInfoService.updateAssetInfo();}
}@Service
public class AssetInfoServiceImpl extends ServiceImpl<AssetInfoMapper, AssetInfoDTO> implements IAssetInfoService {@Autowiredprivate AssetInfoMapper assetInfoMapper;@Override@Transactional(propagation = Propagation.NESTED)public void updateAssetInfo() throws IOException {assetInfoMapper.update(new UpdateWrapper<>(new AssetInfoDTO()).set("asset_status", 99).eq("asset_number", "5277dd895001bbbdb444f174db644d75"));int i = 1 / 0; // 故意抛出异常}
}

测试后查看数据,两个事务都回滚了

t_emp
t_asset_info

2-2、演示使用NESTED传播行为,在内部事务中抛出异常【手动捕获】

注意事项:需要手动捕获内部事务异常

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper, Emp> implements IEmpService {@Autowiredprivate EmpMapper empMapper;@Autowiredprivate AssetInfoServiceImpl assetInfoService;@Override@Transactionalpublic void updateEmpInfo() throws IOException {empMapper.update(new UpdateWrapper<>(new Emp()).set("emp_salary", 114.58).set("emp_name", "一个名字").eq("emp_id", 111));try {assetInfoService.updateAssetInfo();} catch (Exception e) {log.error("updateAssetInfo error", e);}}
}@Service
public class AssetInfoServiceImpl extends ServiceImpl<AssetInfoMapper, AssetInfoDTO> implements IAssetInfoService {@Autowiredprivate AssetInfoMapper assetInfoMapper;@Override@Transactional(propagation = Propagation.NESTED)public void updateAssetInfo() throws IOException {assetInfoMapper.update(new UpdateWrapper<>(new AssetInfoDTO()).set("asset_status", 99).eq("asset_number", "5277dd895001bbbdb444f174db644d75"));int i = 1 / 0; // 故意抛出异常}
}

测试后查看数据,外部事务正常提交,内部事务回滚了

t_emp
t_asset_info

http://www.xdnf.cn/news/364447.html

相关文章:

  • 软件确认报告:审查功能、评估标准及推动软件稳定高效运行
  • 【Cesium入门教程】第五课:数据源
  • JAVA学习-练习试用Java实现“一个游戏AI :如井字游戏(Tic-Tac-Toe)的AI对手”
  • 【二】CURL命令解析
  • 报错 <pcl/features/feature_evaluation/feature_evaluation_framework.h> 不存在的解决办法
  • Java中的控制流语句:if、switch、for、foreach、while、do-while
  • Redis 8.0携新功能,重新开源
  • 【Unity】Unity中修改网格的大小和倾斜网格
  • 如何解决Jmeter中的乱码问题?
  • 【PHP】基于币安链,一个完整的USDT转账示例
  • 【python】 python拆包
  • 【QT】项目打包与发布安装
  • 图灵爬虫练习平台第七题千山鸟飞绝js逆向
  • 宠物医院预约|基于Java+vue的宠物医院预约平台系统(源码+数据库+文档)
  • windows celery OSError: [WinError 6] 句柄无效
  • ELF-如何学习
  • C++(1):整数常量
  • Mysql存储引擎
  • 期刊论文写作注意点
  • LVGL源码学习之渲染、更新过程(1)---标记和激活
  • 【C/C++】为什么要noexcept
  • 机器学习第二讲:对比传统编程:解决复杂规则场景
  • 机器学习实操 第二部分 第19章 大规模训练和部署 TensorFlow 模型
  • RPG11.创建玩家Ability类
  • 基于CNN的猫狗图像分类系统
  • 推荐系统(二十五):基于阿里DIN(Deep Interest Network)的CTR模型实现
  • SpringCloud的作用
  • Java高频基础面试题
  • EMC|AC/DC转换器ESD静电防护
  • The 2024 ICPC Kunming Invitational Contest G. Be Positive