😀前言
本篇是Spring 声明式事务系列的第二篇介绍了Spring 声明式事务机制
🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉😉
🤩声明式事务机制
😄事务的传播机制
事务的传播机制说明
- 当有多个事务处理并存时,如何控制?
- 比如用户去购买两次商品(使用不同的方法), 每个方法都是一个事务,那么如何控制呢?
- 这个就是事务的传播机制,看一个具体的案例(如图)
🥰事务传播机制种类
● 事务传播的属性/种类一览图
● 事务传播的属性/种类机制分析,
重点分析了 REQUIRED 和 REQUIRED_NEW 两种事务 传播属性, 其它知道即可(看上图)
● 事务的传播机制的设置方法
● REQUIRES_NEW 和 REQUIRED 在处理事务的策略
- 如果设置为 REQUIRES_NEW
buyGoods2 如果错误,不会影响到 buyGoods()反之亦然,即它们的事务是独立的.
- 如果设置为 REQUIRED
buyGoods2 和 buyGoods 是一个整体,只要有方法的事务错误,那么两个方法都不会执行成功.!
😋事务的传播机制-应用实例
● 事务的传播机制需要说明
- 比如用户去购买两次商品(使用不同的方法), 每个方法都是一个事务,那么如何控制呢?
=>这个就是事务的传播机制 - 看一个具体的案例(用 required/requires_new 来测试):
修改 GoodsDao.java, 增加方法
public class GoodsDao { /** * 根据商品id,返回对应的价格 * @param id * @return */ public Float queryPriceById2(Integer id) { String sql = "SELECT price From goods Where goods_id=?"; Float price = jdbcTemplate.queryForObject(sql, Float.class, id); return price; } /** * 修改用户的余额 [减少用户余额] * @param user_id * @param money */ public void updateBalance2(Integer user_id, Float money) { String sql = "UPDATE user_account SET money=money-? Where user_id=?"; jdbcTemplate.update(sql, money, user_id); } /** * 修改商品库存 [减少] * @param goods_id * @param amount */ public void updateAmount2(Integer goods_id, int amount){ String sql = "UPDATE goods_amount SET goods_num=goods_num-? Where goods_id=?"; jdbcTemplate.update(sql, amount , goods_id); } }
修改 GoodsService.java 增加 buyGoodsByTx02(), 使用默认的传播机制
注解解读
1. 使用@Transactional 可以进行声明式事务控制
2. 即将标识的方法中的,对数据库的操作作为一个事务管理
3. @Transactional 底层使用的仍然是AOP机制
4. 底层是使用动态代理对象来调用buyGoodsByTx
5. 在执行buyGoodsByTx() 方法 先调用 事务管理器的 doBegin() , 调用 buyGoodsByTx()
如果执行没有发生异常,则调用 事务管理器的 doCommit(), 如果发生异常 调用事务管理器的 doRollback()
@Transactional(propagation = Propagation.REQUIRES_NEW) public void buyGoodsByTx(int userId, int goodsId, int amount) { //输出购买的相关信息 System.out.println("用户购买信息 userId=" + userId + " goodsId=" + goodsId + " 购买数量=" + amount); //1.得到商品的价格 Float price = goodsDao.queryPriceById(userId); //2. 减少用户的余额 goodsDao.updateBalance(userId, price * amount); //3. 减少库存量 goodsDao.updateAmount(goodsId, amount); System.out.println("用户购买成功~"); } @Transactional public void buyGoodsByTx2(int userId, int goodsId, int amount) { //输出购买的相关信息 System.out.println("用户购买信息 userId=" + userId + " goodsId=" + goodsId + " 购买数量=" + amount); //1.得到商品的价格 Float price = goodsDao.queryPriceById2(userId); //2. 减少用户的余额 goodsDao.updateBalance2(userId, price * amount); //3. 减少库存量 goodsDao.updateAmount2(goodsId, amount); System.out.println("用户购买成功~"); }
创建MultiplyService类
解读
- multiBuyGoodsByTx 这个方法 有两次购买商品操作
- buyGoodsByTx 和 buyGoodsByTx2 都是声明式事务
- 当前buyGoodsByTx 和 buyGoodsByTx2 使用的传播属性是默认的 REQUIRED [这个含义前面讲过了
即会当做一个整体事务进行管理 , 比如buyGoodsByTx方法成功,但是buyGoodsByTx2() 失败,会造成 整个事务的回滚 即会回滚buyGoodsByTx - 如果 buyGoodsByTx 和 buyGoodsByTx2 事务传播属性修改成 REQUIRES_NEW
这时两个方法的事务是独立的,也就是如果 buyGoodsByTx成功 buyGoodsByTx2失败, 不会造成 buyGoodsByTx回滚.
@Service public class MultiplyService { @Resource private GoodsService goodsService; @Transactional public void multiBuyGoodsByTx() { goodsService.buyGoodsByTx(1, 1, 1); goodsService.buyGoodsByTx2(1, 1, 1); } }
测试 TxTest.java,
可以验证:为 REQUIRED buyGoodsByTx 和 buyGoodsByTx02 是整体, 只要有方法的事务错误,那么两个方法都不会执行成功
@Test public void buyGoodsByMulTxTest() { ApplicationContext ioc = new ClassPathXmlApplicationContext("tx_ioc.xml"); MultiplyTxService bean = ioc.getBean(MultiplyTxService.class); bean.multiTxTest(); System.out.println("------ok--------"); }
故意写错
修 改 GoodsService.java ,
将 传 播 机 制 改 成 REQUIRES_NEW 可 以 验 证 : 设 置 为 REQUIRES_NEW
buyGoodsByTx 如果错误不会影响到 buyGoodsByTx02()反之亦然,也就 是说它们的事务是独立的
将二个方法的 @Transactional修改为下面的这种形式 完成测试
@Transactional(propagation = Propagation.REQUIRES_NEW)
😄总结
本篇介绍了事务传播机制种类和事务的传播机制-应用实例希望可以帮到大家
😘Spring 声明式事务系列
第一篇–> 什么是Spring 声明式事务详细讲解
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞