Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >并发场景下常见的锁及简单使用

并发场景下常见的锁及简单使用

作者头像
lin_zone
发布于 2020-04-15 10:14:36
发布于 2020-04-15 10:14:36
70700
代码可运行
举报
文章被收录于专栏:LIN_ZONELIN_ZONE
运行总次数:0
代码可运行

1.MySQL悲观锁

悲观锁:顾名思义,对待过来的请求持比较悲观的态度,在处理请求的整个过程中,将数据锁定,不允许其他进程/线程 修改

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
set autocommit=0;
begin;
select * from table where id = xx for update; //互斥锁      //InnoDB 必须明确索引字段的值(查询需走索引),否则会将整个表的数据都加锁
// select * from table where id = xx lock in share mode;		// 共享锁,容易造成死锁,谨慎使用
......
// 对数据进行操作
......
commit;

当session1执行完 select * from table where field = xx for update; (field需要是索引字段) 的时候 就将那一行的数据锁定了,此时 session2 再来执行 for update 或者 修改此条数据的操作的时候就会被阻塞

注:MySQL 悲观锁 虽然数据可以保证绝对正确,但是并发效率极低,一般不使用

  1. MySQL乐观锁 乐观锁:顾名思义,对待过来的请求持比较乐观的态度,先假设不会冲突,在提交更新的时候再去检验数据有没有被其他进程修改过,如果中间有被其他进程修改过起冲突了,则返回错误 乐观锁的实现
  2. 版本控制 感兴趣的话可以看一下MySQL的MVCC的实现原理(InnoDB默认的可重复读隔离级别) MVCC 原理 大致是这样的:

数据库有隐藏的创建版本和删除版本的字段,每次开始事务的时候,事务版本号都会自增

新增数据的时候,在对应的创建版本号的地方填上 当前事务的版本号

更新数据的时候,将要更新的数据行的删除版本号填上当前事务的版本号,然后插入一条新数据,创建版本号 填上 当前事务的版本号

删除数据的时候,将要删除的数据行的删除版本号填上当前事务的版本号

查询数据的时候,查询 删除版本号大于当前事务的版本号 或 创建版本号小于等于当前事务的版本号且删除版本号为空

代码语言:txt
AI代码解释
复制
2.在where 条件中进行限制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 在秒杀场景中的使用
1. 将库存字段设置为 unsigned int 类型,库存一直减,减到负数就直接报错,应用程序捕获这个错误进行处理这种方式依赖数据库抛异常,算是数据库设计的一种技巧,不算乐观锁
2. 更新库存的时候,直接 update table set remain_amount = remain_amount - num where id = xx and remain_amount >= num							// num 是一个
3. 结合 12
 

3.Redis 分布式锁 参考 石杉的架构笔记--Redis分布式锁的实现原理

1.原理大概是这样的(Redis可能是一个集群,这里就当做是单机的场景,集群的话 加锁只给master节点加锁):

  1. Redis 是单进程单线程的,不涉及到锁的问题,至于Redis的并发是借助 I/O多路复用( Epoll)实现
  2. 请求进来后先检查 resource_str 这个hash类型的key存在不,如果不存在,则 hset resource_str client_str 1 ,然后设置一个过期时间;如果resource_str 存在,则 判断 resource_str client_str 存在不,如果存在,延长过期时间;如果不存在则获取一下 resource_str 的过期时间 time,然后client 进入循环等待time 秒 再重新 执行2 这个过程。
  3. 释放锁的时候,直接将 resource_str key 删除即可

释放锁的时候,直接将 resource_str key 删除即可

注:1. resource_str代表资源key client_str 代表客户端字符串或者是session字符串

​ 2. 上述情况如果 time过长,可以直接返回 超时

3.Redis 分布式锁的改进

4.Redis 分布式锁的改进

  1. 上述的Redis 分布式锁是基于一个 redis hash key 来实现的,这样相当于串行化,并发效果也不好,在 石杉的架构笔记--分布式锁高并发优化 中提到了一种办法,分段加锁。分段加锁相当于是把之前的一个大锁分成n个小锁,每个小锁管固定的一部分资源。当请求进来的时候就先利用3.1所述的Redis分布式锁原理选一个资源锁给当前客户端加上,然后判断商品库存满不满足,如果满足的话直接进行 创建订单、减库存、释放锁;如果不满足的话,直接释放当前的锁,再给客户端选下一个资源锁加上 (这个选资源锁的过程可以有一个随机的算法,但是需要保证尽量不重复)。当所有的资源锁都不满足的话,就只能返回库存不足了。
  2. 缺点:
    1. 实现比较复杂
    2. 如果每次下单的数量从一开始就一直大于 分段后的资源数,这种情况会到导致商品卖不完

注:1. 本文根据自己的理解所写,如有不对的地方请及时反馈。

      2. 如需转载,请注明出处:https://cloud.tencent.com/developer/article/1614808

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-04-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
高并发场景下锁的使用技巧
如何确保一个方法,或者一块代码在高并发情况下,同一时间只能被一个线程执行,单体应用可以使用并发处理相关的 API 进行控制,但单体应用架构演变为分布式微服务架构后,跨进程的实例部署,显然就没办法通过应用层锁的机制来控制并发了。
Spark学习技巧
2020/09/08
7560
高并发场景下锁的使用技巧
拼多多二面:高并发场景扣减商品库存如何防止超卖?
相信大家都参与过某某电商的抢购活动,那么大家有没有思考过,在高并发场景下,如何防止商品超卖?这里需要注意哪些问题?
码哥字节
2025/03/11
2160
拼多多二面:高并发场景扣减商品库存如何防止超卖?
基于数据库实现的 “乐观锁” 和 “悲观锁”
有一个资源正在被操作的时候,不希望被其它人操作,此时就需要通过加锁来防止这种情况的出现。
软件书桌
2024/04/11
3090
以超卖为例✨各种场景下如何防止并发污染数据?
比如:商品库存扣减、用户余额调整、火车票、机票、演唱会入场票的扣减(类似商品库存扣减)等...
菜菜的后端私房菜
2024/08/13
2871
我们来谈下高并发和分布式中的幂等处理
在编程中,一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数。
搜云库技术团队
2019/10/17
4180
我们来谈下高并发和分布式中的幂等处理
幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
lyb-geek
2018/12/27
5480
2025春招,高级程序员回答数据库问题
以下是V 哥对2025年数据库相关高频面试题的汇总整理,结合了MySQL的核心知识点和大厂实际考察方向,涵盖索引、事务、存储引擎、锁机制、优化策略等关键内容。
威哥爱编程
2025/02/10
2110
高并发下接口幂等性解决方案
在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数. 更复杂的操作幂等保证是利用唯一交易号(流水号)实现.
BUG弄潮儿
2020/06/15
5250
聊聊 13 种锁的实现方式
最近有很多小伙伴给我留言,分布式系统时代,线程并发,资源抢占,"锁" 慢慢变得很重要。那么常见的锁都有哪些?
微观技术
2022/09/28
3610
聊聊 13 种锁的实现方式
架构师带你玩转分布式锁
大多数互联网系统都是分布式部署的,分布式部署确实能带来性能和效率上的提升,但为此,我们就需要多解决一个分布式环境下,数据一致性的问题。
CSDN技术头条
2019/11/19
3070
架构师带你玩转分布式锁
架构师带你玩转分布式锁
大多数互联网系统都是分布式部署的,分布式部署确实能带来性能和效率上的提升,但为此,我们就需要多解决一个分布式环境下,数据一致性的问题。
纯洁的微笑
2018/09/30
4000
架构师带你玩转分布式锁
基于数据库(MySQL)与缓存(Redis)实现分布式锁
分布式锁:分布式锁是在分布式的情况下实现互斥类型的一种锁 实现分布式锁需要满足的五个条件
才疏学浅的木子
2023/11/18
6920
基于数据库(MySQL)与缓存(Redis)实现分布式锁
Redis解决秒杀下单
上述就是实现最基本的优惠卷下单功能。当然真实的业务场景绝对不会是向我们这么简单的。
用户11097514
2024/05/30
1920
Redis解决秒杀下单
高并发的核心技术-幂等的实现方案
一、背景 我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。 例如: 1. 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果。 2. 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱; 3. 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的; 4. 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题。 等等很多重要的情况,这些逻辑都需要幂等的特性来支持。 二、幂等性概念 幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数. 更复杂的操作幂等保证是利用唯一交易号(流水号)实现. 我的理解:幂等就是一个操作,不论执行多少次,产生的效果和返回的结果都是一样的 三、技术方案 1. 查询操作 查询一次和查询多次,在数据不变的情况下,查询结果是一样的。select是天然的幂等操作 2. 删除操作 删除操作也是幂等的,删除一次和多次删除都是把数据删除。(注意可能返回结果不一样,删除的数据不存在,返回0,删除的数据多条,返回结果多个) 3.唯一索引,防止新增脏数据 比如:支付宝的资金账户,支付宝也有用户账户,每个用户只能有一个资金账户,怎么防止给用户创建资金账户多个,那么给资金账户表中的用户ID加唯一索引,所以一个用户新增成功一个资金账户记录 要点: 唯一索引或唯一组合索引来防止新增数据存在脏数据 (当表存在唯一索引,并发时新增报错时,再查询一次就可以了,数据应该已经存在了,返回结果即可) 4. token机制,防止页面重复提交 业务要求: 页面的数据只能被点击提交一次 发生原因: 由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交 解决办法: 集群环境:采用token加redis(redis单线程的,处理需要排队) 单JVM环境:采用token加redis或token加jvm内存 处理流程: 1. 数据提交前要向服务的申请token,token放到redis或jvm内存,token有效时间 2. 提交后后台校验token,同时删除token,生成新的token返回 token特点: 要申请,一次有效性,可以限流 注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用 5. 悲观锁 获取数据的时候加锁获取 select * from table_xxx where id='xxx' for update; 注意:id字段一定是主键或者唯一索引,不然是锁表,会死人的 悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用 6. 乐观锁 乐观锁只是在更新数据那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高。 乐观锁的实现方式多种多样可以通过version或者其他状态条件: 1. 通过版本号实现 update table_xxx set name=#name#,version=version+1 where version=#version# 如下图(来自网上):
lyb-geek
2018/07/26
4220
高并发的核心技术-幂等的实现方案
高并发下接口幂等性解决方案
我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。例如1. 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果;2. 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱;3. 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的;4. 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题等等很多重要的情况都需要幂等的特性来支持。
用户2781897
2021/01/13
4590
高并发下接口幂等性解决方案
面试必备:聊聊分布式锁的多种实现!
大家好,我是捡田螺的小男孩。今天跟大家探讨一下分布式锁的设计与实现。希望对大家有帮助,如果有不正确的地方,欢迎指出,一起学习,一起进步哈~
捡田螺的小男孩
2022/05/23
3450
面试必备:聊聊分布式锁的多种实现!
Springboot分别使用乐观锁和分布式锁(基于redisson)完成高并发防超卖
在电商中经常会有防超卖的需求,本质上是对一条数据的多线程并发情况下的数据安全性进行控制。
天涯泪小武
2019/05/15
4.5K0
MySQL的悲观锁和乐观锁
在分布式系统的大环境下,各种锁机制扮演着重要角色:从宏观的分布式锁到微观的代码锁,再到数据库层面的锁。尽管锁的类型繁多且复杂,但它们的核心功能是一致的:确保在某一时刻,仅有一个线程能够执行操作,其他线程则需等待锁的释放才能继续运行。
写bug的高哈哈
2024/11/02
2490
MySQL的悲观锁和乐观锁
分布式锁的3种实现!附代码
分布式锁是一种用于保证分布式系统中多个进程或线程同步访问共享资源的技术。同时它又是面试中的常见问题,所以我们本文就重点来看分布式锁的具体实现(含实现代码)。
磊哥
2023/09/13
3550
万字长文!分布式锁的实现全都在这里了
最近老板接了一个大单子,允许在某终端设备安装我们的APP,终端设备厂商日活起码得几十万到百万级别,这个APP也是近期产品根据市场竞品分析设计出来的,几个小码农通宵达旦开发出来的,主要功能是在线购物一站式服务,后台可以给各个商家分配权限,来维护需要售卖的商品信息。
数据和云
2020/02/13
8620
相关推荐
高并发场景下锁的使用技巧
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档