前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >并发场景下常见的锁及简单使用

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

作者头像
lin_zone
发布2020-04-15 18:14:36
6670
发布2020-04-15 18:14:36
举报
文章被收录于专栏:LIN_ZONE

1.MySQL悲观锁

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

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

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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档