zoukankan      html  css  js  c++  java
  • spring事务详解(二)实例

    在Spring中,事务有两种实现方式:

    编程式事务管理: 编程式事务管理使用底层源码可实现更细粒度的事务控制。spring推荐使用TransactionTemplate,典型的模板模式。

    申明式事务管理: 添加@Transactional注解,并定义传播机制+回滚策略。基于Spring AOP实现,本质是对方法前后进行拦截,

    方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

    关于spring事务实现方式:

    引用博文:https://www.cnblogs.com/dennyzhangdd/p/9708499.html

    关于分布式锁的实现方式:

    引用博文:https://www.cnblogs.com/dennyzhangdd/p/7133653.html

    提供一个具体实例来说明如何使用spring事务

    基于数据库锁实现

     1.悲观锁:select for update(一致性锁定读)


    查询官方文档如上图,事务内起作用的行锁。能够保证当前session事务所锁定的行不会被其他session所修改(这里的修改指更新或者删除)。
    对读取的记录加X锁,即排它锁,其他事不能对上锁的行加任何锁。
    
    BEGIN;(确保以下2步骤在一个事务中:)
    SELECT * FROM tb_product_stock WHERE product_id=1 FOR UPDATE--->product_id有索引,锁行.加锁
    (注:条件字段必须有索引才能锁行,否则锁表,且最好用explain查看一下是否使用了索引,因为有一些会被优化掉最终没有使用索引)
    UPDATE tb_product_stock SET number=number-1 WHERE product_id=1--->更新库存-1.解锁
    COMMIT; 
    
    

    2.乐观锁:版本控制

    选一个字段作为版本控制字段,更新前查询一次,更新时该字段作为更新条件
    不同业务场景,版本控制字段,可以0 1控制,也可以+1控制,也可以-1控制,这个随意。
    BEGIN;(确保以下2步骤在一个事务中:)
    SELECT number FROM tb_product_stock WHERE product_id=1--》查询库存总数,不加锁
    UPDATE tb_product_stock SET number=number-1 WHERE product_id=1 AND number=第一步查询到的库存数--》number字段作为版本控制字段
    COMMIT; 

    场景举例:

    卖商品,先查询库存>0,更新库存-1。

    例如:一种商品,有两件库存,多人来下单买,一个人一次只能买一件商品

    创建表biz_shoe

    1 CREATE TABLE `biz_shoe` (
    2   `shoe_uuid` char(32) NOT NULL,
    3   `inventory_number` int(11) DEFAULT NULL COMMENT '库存数量',
    4   `is_putaway` int(1) DEFAULT NULL COMMENT '是否上架',
    5   PRIMARY KEY (`shoe_uuid`)
    6 ) ENGINE=InnoDB DEFAULT CHARSET=utf8

    给库存赋值,如图

    3.基于悲观锁实现

     1   /**
     2      * 悲观锁
     3      * @param shoe
     4      * @return
     5      */
     6     @Transactional(添加spring事务注解)
     7     @Override
     8     public Integer vieShoe(BizShoe shoe) {
     9         //抢单商品加悲观锁
    10         BizShoe modleShoe = shoeMapper.lockForUpdate(shoe.getShoeUuid());
    11         //商品库存
    12         Integer number = modleShoe.getInventoryNumber();
    13         System.out.println("库存:" + number);
    14         System.out.println("线程名称:" + Thread.currentThread().getName());
    15         if (number != 0) {
    16             number = number - 1;
    17             System.out.println("剩余库存:" + number);
    18             modleShoe.setInventoryNumber(number);
    19             shoeMapper.updateByPrimaryKeySelective(modleShoe);
    20         } else {
    21             AssertUtil.isTrue(number == 0, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
    22         }
    23         return number;
    24     }

    在mapping中具体sql语句  

    1   <select id="lockForUpdate" parameterType="java.lang.String" resultMap="BaseResultMap">
    2 
    3     SELECT <include refid="Base_Column_List" /> FROM `biz_shoe` WHERE shoe_uuid = #{shoeUuid,jdbcType=CHAR} FOR UPDATE;
    4 
    5   </select>

    4.基于乐观锁

     1   /**
     2      * 乐观锁
     3      * @param shoe
     4      * @return
     5      */
     6     @Transactional
     7     @Override
     8     public Integer vieShoe(BizShoe shoe) {
     9 
    10         //抢单商品加乐观锁
    11         BizShoe modleShoe = shoeMapper.selectByPrimaryKey(shoe.getShoeUuid());
    12         //商品库存
    13         Integer number = modleShoe.getInventoryNumber();
    14         System.out.println("库存:" + number);
    15         System.out.println("线程名称:" + Thread.currentThread().getName());
    16         if(number >0){
    17             int susus = shoeMapper.updateByShoeUuidInventoryNumber(shoe.getShoeUuid(),number);
    18             System.out.println("更新成功 "+susus);
    19             if(susus==1){//更新成功才算抢单成功
    20                 //商品库存
    21                 BizShoe modleShoeNew = shoeMapper.selectByPrimaryKey(shoe.getShoeUuid());
    22                 System.out.println("新库存:" + modleShoeNew.getInventoryNumber());
    23             }else{
    24                 AssertUtil.isTrue(true, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
    25             }
    26         }else {
    27             AssertUtil.isTrue(true, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
    28         }
    29         return number;
    30     }

    sql语句

    1 <update id="updateByShoeUuidInventoryNumber" parameterType="com.zstax.springtest.bean.BizShoe">
    2 
    3     UPDATE biz_shoe SET inventory_number=inventory_number-1 WHERE
    4     shoe_uuid=#{shoeUuid,jdbcType=CHAR} and inventory_number=#{InventoryNumber,jdbcType=INTEGER}
    5 
    6   </update>
  • 相关阅读:
    HDU
    Hdu 5072 Coprime(容斥+同色三角形)
    HDU
    HTML常用基础标签
    简单session实现
    前端中的 IoC 理念
    怎样做页面界限
    Reset 对象属性
    SQL注入
    js:表单校验(获取元素、事件)
  • 原文地址:https://www.cnblogs.com/sqy123/p/10354498.html
Copyright © 2011-2022 走看看