一,为什么要使用分布式锁?

如果在并发时锁定代码的执行,java中用synchronized锁保证了线程的原子性和可见性
但java锁只在单机上有效,如果是多台服务器上的并发访问,则需要使用分布式锁,
例如:两台机器上同时各有一个进程查询同一件商品的库存,此时商品库存数为1,
数据库给两台机器返回的都是1,
然后这两台机器同时下单,两个订单就超出了商品的库存数,
所以此时要使用分布式锁
 

说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

对应的源码可以访问这里获取: https://github.com/liuhongdi/

说明:作者:刘宏缔 邮箱: 371125307@qq.com

 

二,使用redisson

redisson是对redis用java语言的封装
1,redisson的官网:
https://redisson.org/
2,redisson的官方文档:
https://github.com/redisson/redisson/wiki
3,使用redisson做分布式锁和mysql悲观锁(for update)的区别:
   本质上没有区别,
   但redis性能更强
 

三,演示项目的相关信息

1,地址
https://github.com/liuhongdi/distributedlock
2,原理:
  在减库存之前,先加锁,
  在减库存完成后,解锁
  这样避免高并发时查询到相同的库存数而导致超卖情况
 
3,结构
 
 
4,数据表:
CREATE TABLE `goods` (
`goods_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`goods_name` varchar(500) NOT NULL DEFAULT '' COMMENT 'name',
`stock` int(11) NOT NULL DEFAULT '0' COMMENT 'stock',
PRIMARY KEY (`goods_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品表'

四,java代码的说明

OrderServiceImpl.java
@Service
public class OrderServiceImpl implements OrderService { @Resource
private RedissonClient redissonClient;
@Resource
private GoodsMapper goodsMapper; /*
* 加锁减库存
* */
@Override
public boolean decrementProductStoreLock(int goodsId, int buyNum) {
String key = "dec_store_lock_" + goodsId;
//生成锁对象
RLock lock = redissonClient.getLock(key);
try {
//2, TimeUnit.MINUTES
lock.lock(2, TimeUnit.MINUTES);
boolean upRes = updateGoodsStock(goodsId, buyNum);
if (upRes == false) {
return false;
}
} catch (Exception e) {
System.out.println(e.getMessage());
return false;
} finally {
//解锁
if (lock.isHeldByCurrentThread()){
System.out.println("----------------release lock");
lock.unlock();
}
}
return true;
} /*
* 减库存
* */
@Transactional(isolation = Isolation.REPEATABLE_READ)
public boolean updateGoodsStock(int goodsId, int buyNum) {
Goods goodsOne = goodsMapper.selectOneGoods(goodsId);
System.out.println("-------------------------当前库存:"+goodsOne.getStock()+"-------购买数量:"+buyNum);
if (goodsOne.getStock() < buyNum || goodsOne.getStock() <= 0) {
System.out.println("------------------------fail:buy fail,return");
return false;
}
int upStock = goodsOne.getStock()-buyNum;
goodsOne.setStock(upStock);
int upNum = goodsMapper.updateOneGoodsStock(goodsOne);
System.out.println("-------------------------success:成交订单数量:"+upNum);
return true;
} /*
* 不加锁减库存
* */
@Override
public boolean decrementProductStoreNoLock(int goodsId, int buyNum) {
return updateGoodsStock(goodsId, buyNum);
}
}
 
java代码说明:
String key = "dec_store_lock_" + goodsId:  加锁时加入商品id,这样不影响其他商品
RLock是redisson中定义的可重入锁
 lock.lock(2, TimeUnit.MINUTES)   加锁,时长两分钟
lock.unlock(); 解锁
 

五,测试高并发时加锁的效果:

1,数据库的数据:
mysql> update goods set stock=3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from goods;
+----------+------------+-------+
| goods_id | goods_name | stock |
+----------+------------+-------+
| 3 | green cup2 | 3 |
+----------+------------+-------+
1 row in set (0.00 sec)

我们设置商品的库存数为3

2,不加锁的情况
#-c:请求并发数
#-n:请求总数
[root@localhost ~]# ab -c 20 -n 20 http://127.0.0.1:8080/lock/buynolock

查看代码的打印输出:

-------------------------当前库存:3-------购买数量:1
-------------------------success:成交订单数量:1
-------------------------当前库存:2-------购买数量:1
-------------------------success:成交订单数量:1
-------------------------当前库存:1-------购买数量:1
-------------------------当前库存:1-------购买数量:1
-------------------------当前库存:1-------购买数量:1
-------------------------success:成交订单数量:1
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------success:成交订单数量:1
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------success:成交订单数量:1
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
共成交5单,超出了库存数量
 
3,加锁的情况:
#-c:请求并发数
#-n:请求总数
[root@localhost ~]# ab -c 20 -n 20 http://127.0.0.1:8080/lock/buylock

查看代码的打印输出:

-------------------------当前库存:3-------购买数量:1
-------------------------success:成交订单数量:1
-------------------------当前库存:2-------购买数量:1
-------------------------success:成交订单数量:1
-------------------------当前库存:1-------购买数量:1
-------------------------success:成交订单数量:1
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return
-------------------------当前库存:0-------购买数量:1
------------------------fail:buy fail,return

只成功了3个订单,说明分布式锁有效

六,查看spring boot的版本:

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.0.RELEASE)

spring boot:用redis+redisson实现分布式锁(redisson3.11.1/spring boot 2.2)的更多相关文章

  1. 使用Redisson实现分布式锁,Spring AOP简化之

    源码 Redisson概述 Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid).它不仅提供了一系列的分布式的Java常用对象,还提供了许多 ...

  2. Redisson实现分布式锁

    转: Redisson实现分布式锁 Redisson文档参考:https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95 redis是实现 ...

  3. 利用Redisson实现分布式锁及其底层原理解析

    Redis介绍 参考地址:https://blog.csdn.net/turbo_zone/article/details/83422215 redis是一个key-value存储系统.和Memcac ...

  4. Springboot中使用Redisson实现分布式锁

    1. 概述 老话说的好:便宜没好货,有价值的商品,即使再贵,也有人会买. 言归正传,今天继续讨论有关"锁"的话题,synchronized 和 ReentrantLock 大家应该 ...

  5. redis客户端、分布式锁及数据一致性

    Redis Java客户端有很多的开源产品比如Redission.Jedis.lettuce等. Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持:Redis ...

  6. Redis系列(二)--分布式锁、分布式ID简单实现及思路

    分布式锁: Redis可以实现分布式锁,只是讨论Redis的实现思路,而真的实现分布式锁,Zookeeper更加可靠 为什么使用分布式锁: 单机环境下只存在多线程,通过同步操作就可以实现对并发环境的安 ...

  7. Redisson实现分布式锁(3)—项目落地实现

    Redisson实现分布式锁(3)-项目落地实现 有关Redisson实现分布式锁前面写了两篇博客作为该项目落地的铺垫. 1.Redisson实现分布式锁(1)---原理 2.Redisson实现分布 ...

  8. Redisson实现分布式锁(2)—RedissonLock

    Redisson实现分布式锁(2)-RedissonLock 有关Redisson实现分布式锁上一篇博客讲了分布式的锁原理:Redisson实现分布式锁---原理 这篇主要讲RedissonLock和 ...

  9. Redisson实现分布式锁(1)---原理

    Redisson实现分布式锁(1)---原理 有关Redisson作为实现分布式锁,总的分3大模块来讲. 1.Redisson实现分布式锁原理 2.Redisson实现分布式锁的源码解析 3.Redi ...

随机推荐

  1. 口罩预约管理系统——数据库设计(前端+PHP+MySQL)

    目录 一.背景 二.口罩预约管理系统介绍 三.数据库设计 四.MySQL创建数据库以及数据表 五.数据库设计总结 一.背景 2020年的疫情影响了我们的生产生活,政府不断加大力度联防联控,遏制疫情的蔓 ...

  2. C# 中 Struct 和 Class 的区别总结

    翻译自 Manju lata Yadav 2019年6月2日 的博文 <Difference Between Struct And Class In C#>,补充了一些内容和示例. 结构体 ...

  3. Windows Server系统部署MySQL数据库

    由于工作需要在阿里云服务器中使用MySQL,所以安装一下MySQL数据库,中间也踩了一些坑,现在将整个过程给大家记录下来,便于后续查找. 阿里云服务器是WinServer2012系统,之前在Windo ...

  4. 8.Kafka offset机制

  5. Element-UI:级联选择器:Cannot read property 'level' of null"

    当级联选择时如果其选择内容需要动态变化时,如果没有选择就不会报错的:而当做出选择后又要动态变化级联选择器内容时,就会报错/ 错误:这个错误的原因是当选择后,再更新内容时,选择器仍会关联原来的数据,导致 ...

  6. 容器云平台No.5~企业级私有镜像仓库Harbor V2.02

    镜像仓库 仓库,顾名思义,就是存放东西的地方,Docker仓库,理所当然,就是存放docker镜像的地方了. Docker仓库分公有仓库和私有仓库.共有仓库有hub.docker.com.gcr.io ...

  7. jwt攻击手段

    jwt 秘钥泄漏/敏感文件泄漏 在一些配置文件被我们可查的情况下,包括各种文件读取,源码泄漏,此时伪造身份就变得很容易了. 空加密算法 对于明文的加密算法通常为HS256,在jwt中分为三个部分,以点 ...

  8. python ---倒酒!!

    #!/usr/bin/env python3# -*- coding: utf-8 -*-import numbersimport numpyimport math'''三个容器分别为12升.8升.5 ...

  9. IntelliJ IDEA 2020.2 x64 最新破解教程有效期到2089年 完全免费分享

    作者:极客小俊 一个专注于web技术的80后 我不用拼过聪明人,我只需要拼过那些懒人 我就一定会超越大部分人! CSDN@极客小俊,原创文章, B站技术分享 B站视频 : Bilibili.com 个 ...

  10. netty关键字

    ------------恢复内容开始------------ buffer 本质读写的内存,三个属性:capacity.position和limit capacity:容器大小 position:读写 ...