MySql系列(实战):mysql增加version字段实现乐观锁

导读:本篇文章讲解 MySql系列(实战):mysql增加version字段实现乐观锁,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

MySql系列(实战):mysql增加version字段实现乐观锁


前言

今天博主将为大家分享:MySql系列(实战):mysql增加version字段实现乐观锁!不喜勿喷,如有异议欢迎讨论!首先推荐大家去看我的MySql查询优化MySql系列:MySQL 之 Explain 输出分析 等系列文章!


多线程条件同行工具简述

有兴趣请查看历史文章:Java系列:多线程条件通行工具——CyclicBarrierJava系列:Java 多线程条件通行工具——CountDownLatch

在这里插入图片描述

先说说同一个事务中使用一个乐观锁的情况:


先做查询 【查询时候把version带出来】
<select id="findByUid" parameterType="String" resultType="com.sxd.swapping.domain.GoodsStock">
        select
        uid uid,
        version version,
        sale_num saleNum,
        stock stock
        from
        goods_stock
        where
        uid = #{uid}

</select>
再做更新【更新的时候判断version是不是查出来时候的version,如果是,则更新,更新时顺便version+1即可。否则不更新】

update goods_stock set stock = stock – #{buyNum}, sale_num = sale_num + #{buyNum}, version = version + 1 where uid = #{uid} and version = #{version}

实体对应数据表

/**
*

  • @Description: 低配商品库存表

  • @ClassName: GoodsStock .java

  • @author ChenYongJia

  • @Date 2019年6月13日 晚上21:23

  • @Email chen87647213@163.com
    */
    @Entity
    @Table
    @Getter
    @Setter
    public class GoodsStock implements Serializable {

    private String goodsName;//商品名称

    private String goodsPrice;//商品价格

    private Long buyNum;//购买数量

    private Long saleNum;//销售量

    private Long stock;//商品库存 库存为-1 代表无限量库存

    private Integer version;//版本号 默认初始版本为0
    @Transient
    private Integer threadCount;//模拟并发访问的线程数量 实际业务中不用这个字段 仅用本次测试接口使用
    }

mybatis的mapper.xml

<?xml version=”1.0″ encoding=”UTF-8″ ?>

<update id="updateStock" parameterType="com.cyj.entity.GoodsStock">
    update
    goods_stock
    set
    <if test="stock != -1">
        stock = stock - #{buyNum},
    </if>
    sale_num = sale_num + #{buyNum},
    version  = version + 1
    where
    uid = #{uid}
    and
    version = #{version}
</update>


<select id="findByUid" parameterType="String" resultType="com.cyj.entity.GoodsStock">
    select
    uid uid,
    version version,
    sale_num saleNum,
    stock stock
    from
    goods_stock
    where
    uid = #{uid}

</select>
mybatis的mapper.java

package com.cyj.dao.mybatis;
import com.cyj.domain.GoodsStock;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
*

  • @Description: 低配版商品库存表dao
  • @ClassName: GoodsStockMapper .java
  • @author ChenYongJia
  • @Date 2019年6月13日 晚上21:18
  • @Email chen87647213@163.com
    */
    @Mapper
    public interface GoodsStockMapper {

/**
* 修改商品库存表信息
*
* @param goodsStock
* @return
*/
int updateStock(GoodsStock goodsStock);

/**
* 根据uid查询低配商品库存表
*
* @param uid
* @return
*/
GoodsStock findByUid(@Param(“uid”) String uid);

}

serviceImpl层代码

@Autowired
GoodsStockMapper mapper;

/**
 * 数据库加 version 版本号
 *
 * 实现 数据库乐观锁
 *
 * 实现高并发下库存的并发控制机制
 *
 * 要保证事务一致性,要么都使用mybatis  要么都使用jpa
 * @param map
 * @param entity
 * @param threadNum
 * @return
 */
@Override
@Transactional
public void updateStock(Map<Integer,String> map, GoodsStock entity, Integer threadNum) {

    String  uid = entity.getUid();
    Long buyNum = entity.getBuyNum();
    String msg = "";
    //判断库存是否足够
    GoodsStock old = mapper.findByUid(uid);
    Long stock = old.getStock();
    System.out.println("线程"+threadNum+"---------->正在工作");
    if (stock >= buyNum){
        old.setBuyNum(buyNum);
        if (mapper.updateStock(old) > 0 ){
            msg = "库存扣除成功,剩余库存数量:";
        }else {
            msg = "库存扣除失败,剩余库存数量:";
        }
        Long nowStock = mapper.findByUid(uid).getStock();
        msg +=nowStock;
    }else {
        msg = "库存不足,剩余库存数量:"+stock;
    }
    map.put(threadNum,msg);
}
controller层代码:

/**
* uid代表 同一时间 大家都来买这一件东西
* threadCount代表 同时会有多少人在操作
* buyNum代表 同一个人的一次购买量
* @param entity
* @return
*/
@RequestMapping(value = “/concurrentStock”,method = RequestMethod.POST)
public UniVerResponse<Map<Integer,String>> concurrentStock(@RequestBody GoodsStock entity){
UniVerResponse.checkField(entity,“uid”,“threadCount”,“buyNum”);
UniVerResponse<Map<Integer,String>> res = new UniVerResponse<>();

    String uid = entity.getUid();

    GoodsStock old = service.findByUid(uid);
    if (old != null){
        //设置一个线程安全的Map记录各个线程是否成功执行
        Map<Integer,String> map = new ConcurrentHashMap<Integer, String>();


        Integer threadCount = entity.getThreadCount();
        //所有线程阻塞,然后统一开始
        CountDownLatch begin = new CountDownLatch(1);

        //主线程阻塞,直到所有分线程执行完毕
        CountDownLatch end = new CountDownLatch(threadCount);

        //开始多线程            begin.countDown();
        for (Integer i = 0; i < threadCount; i++) {
            Runnable runnable = buyGoods(map,entity,i,begin,end);
            new Thread(runnable).start();
        }

        //多个线程都执行结束
        try {
            end.await();
            res.beTrue(map);
        } catch (InterruptedException e) {
            e.printStackTrace();
            res.beFalse("多线程执行失败",UniVerResponse.ERROR_BUSINESS,null);
        }
    }else {
        res.beFalse("商品不存在",UniVerResponse.ERROR_BUSINESS,null);
    }
    return  res;
}


//多线程的方法
public Runnable buyGoods(Map<Integer,String> map, GoodsStock entity, Integer threadNum,CountDownLatch begin,CountDownLatch end){
    Runnable runnable = new Runnable() {
        @Override
        public void run() {

            try {
                System.out.println("线程"+threadNum+":--------------------->开始工作");
                begin.await();

                service.updateStock(map,entity,threadNum);

                end.countDown();
                System.out.println("线程"+threadNum+":--------------------->结束工作");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    };
    return runnable;

}

每当同一时间比如10个人同事发送请求后,线程同行工具执行完毕时,每有一个购买成功时版本号version会+1购买失败不+1


到这里:MySql系列(实战):mysql增加version字段实现乐观锁!,分享完毕了,快去试试吧!


最后

  • 更多参考精彩博文请看这里:《陈永佳的博客》

  • 喜欢博主的小伙伴可以加个关注、点个赞哦,持续更新嘿嘿!


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/97817.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!