Spring 声明式事务机制

简介: Spring 声明式事务机制

?前言

本篇是Spring 声明式事务系列的第二篇介绍了Spring 声明式事务机制

?个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力??


?声明式事务机制

?事务的传播机制

事务的传播机制说明

  1. 当有多个事务处理并存时,如何控制?
  2. 比如用户去购买两次商品(使用不同的方法), 每个方法都是一个事务,那么如何控制呢?
  3. 这个就是事务的传播机制,看一个具体的案例(如图)

?事务传播机制种类

● 事务传播的属性/种类一览图

● 事务传播的属性/种类机制分析,

重点分析了 REQUIRED 和 REQUIRED_NEW 两种事务 传播属性, 其它知道即可(看上图)

● 事务的传播机制的设置方法

● REQUIRES_NEW 和 REQUIRED 在处理事务的策略

  1. 如果设置为 REQUIRES_NEW

buyGoods2 如果错误,不会影响到 buyGoods()反之亦然,即它们的事务是独立的.

  1. 如果设置为 REQUIRED

buyGoods2 和 buyGoods 是一个整体,只要有方法的事务错误,那么两个方法都不会执行成功.!

?事务的传播机制-应用实例

● 事务的传播机制需要说明

  1. 比如用户去购买两次商品(使用不同的方法), 每个方法都是一个事务,那么如何控制呢?
    =>这个就是事务的传播机制
  2. 看一个具体的案例(用 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类

解读

  1. multiBuyGoodsByTx 这个方法 有两次购买商品操作
  2. buyGoodsByTx 和 buyGoodsByTx2 都是声明式事务
  3. 当前buyGoodsByTx 和 buyGoodsByTx2 使用的传播属性是默认的 REQUIRED [这个含义前面讲过了
    即会当做一个整体事务进行管理 , 比如buyGoodsByTx方法成功,但是buyGoodsByTx2() 失败,会造成 整个事务的回滚 即会回滚buyGoodsByTx
  4. 如果 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连支持一下,创造不易您们的支持是我的动力?


目录
相关文章
|
1天前
|
Java 数据库 开发者
|
1天前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
22 0
|
1天前
|
SQL Java 关系型数据库
Spring 事务
Spring 事务
12 1
|
1天前
|
Java 数据库连接 数据库
Spring事务简介,事务角色,事务属性
Spring事务简介,事务角色,事务属性
18 2
|
1天前
|
缓存 NoSQL Java
17:缓存机制-Java Spring
17:缓存机制-Java Spring
41 5
|
1天前
|
Java 数据库连接 数据库
16:事务-Java Spring
16:事务-Java Spring
29 5
|
1天前
|
消息中间件 Java 关系型数据库
Spring事务与分布式事务
这篇文档介绍了事务的概念和数据库事务的ACID特性:原子性、一致性、隔离性和持久性。在并发环境下,事务可能出现更新丢失、脏读和不可重复读等问题,这些问题通过设置事务隔离级别(如读未提交、读已提交、可重复读和序列化)来解决。Spring事务传播行为有七种模式,影响嵌套事务的执行方式。`@Transactional`注解用于管理事务,其属性包括传播行为、隔离级别、超时和只读等。最后提到了分布式事务,分为跨库和跨服务两种情况,跨服务的分布式事务通常通过最终一致性策略,如消息队列实现。
|
1天前
|
安全 Java 测试技术
利用Java反射机制提高Spring Boot的代码质量:概念与实战
【4月更文挑战第29天】Java反射机制提供了一种强大的方法来在运行时检查或修改类和对象的行为。在Spring Boot应用中,合理利用反射可以提高代码的灵活性和可维护性。本篇博客将探讨Java反射的核心概念,并展示如何通过反射提高Spring Boot项目的代码质量。
29 0
|
1天前
|
监控 Java 测试技术
Spring Boot与事务钩子函数:概念与实战
【4月更文挑战第29天】在复杂的业务逻辑中,事务管理是确保数据一致性和完整性的关键。Spring Boot提供了强大的事务管理机制,其中事务钩子函数(Transaction Hooks)允许开发者在事务的不同阶段插入自定义逻辑。本篇博客将详细探讨事务钩子函数的概念及其在Spring Boot中的应用。
37 1
|
1天前
|
XML Java 数据库连接
精妙绝伦:玩转Spring事务编程的艺术
【4月更文挑战第20天】
31 0
http://www.vxiaotou.com