Mysql的排他锁和共享锁
今天看代码看到有select name from user where id = 1 for update,有点懵逼,完全没有见过,只能说自己见识少了,那就只能学习一下。先做一下基本知识了解(大部分都是整理了别人的文档,如有侵权还请告知):
锁的基本概念
当多事务争取一个资源时,有可能导致数据不一致,这个时候需要一种机制限制,并且将数据访问顺序化,用来保证数据库数据的一致性,锁就是其中的一种机制。我们可以用商场的试衣间来做个比喻,商场里得每个试衣间都可供多个消费者使用,因此可能出现多个消费者同时试衣服需要使用试衣间,这时候就产生冲突了,为了避免冲突,试衣间装了锁(其实就是进去之后把门拴住),某一个试衣服的人在试衣间里把锁锁住了,其他顾客就不能再从外面打开了,只能等待里面的顾客,试完衣服,从里面把锁打开,外面的人才能进去(网上找到的比喻,非常形象)。不过我想要是并发了就尴尬了,哈哈。
锁的基本类型
数据库上的操作可以归纳为两种:读和写。
多个事务同时读取一个对象的时候,是不会有冲突的。同时读和写,或者同时写才会产生冲突。因此为了提高数据库的并发性能,通常会定义两种锁:共享锁和排它锁。
共享锁(Shared Lock,也叫S锁)
共享锁(S)表示对数据进行读操作。因此多个事务可以同时为一个对象加共享锁。(如果试衣间的门还没被锁上,顾客都能够同时进去参观)
产生共享锁的sql:select * from ad_plan lock in share mode;
共享锁的使用场景
SELECT ... LOCK IN SHARE MODE走的是IS锁(意向共享锁),即在符合条件的rows上都加了共享锁,这样的话,其他人可以读取这些记录,也可以继续添加IS锁,但是无法修改这些记录直到你这个加锁的过程执行完成(完成的情况有:事务的提交,事务的回滚,否则直接锁等待超时)。
SELECT ... LOCK IN SHARE MODE的应用场景适合于两张表存在关系时的写操作,拿mysql官方文档的例子来说,一个表是child表,一个是parent表,假设child表的某一列child_id映射到parent表的c_child_id列,那么从业务角度讲,此时我直接insert一条child_id=100记录到child表是存在风险的,因为刚insert的时候可能在parent表里删除了这条c_child_id=100的记录,那么业务数据就存在不一致的风险。正确的方法是再插入时执行select * from parent where c_child_id=100 lock in share mode,锁定了parent表的这条记录,然后执行insert into child(child_id) values (100)就不会存在这种问题了。
排他锁(Exclusive Lock,也叫X锁)
排他锁也叫写锁(X)。
排他锁表示对数据进行写操作。如果一个事务对对象加了排他锁,其他事务就不能再给它加任何锁了。(某个顾客把试衣间从里面反锁了,其他顾客想要使用这个试衣间,就只有等待锁从里面给打开了)
产生排他锁的sql: select * from ad_plan for update;看到了吧,for update出现了,所以for update 是排他锁,涨知识了。
排他锁的使用场景:
使用场景一:订单的商品数量
但是如果是同一张表的应用场景,举个例子,电商系统中计算一种商品的剩余数量,在产生订单之前需要确认商品数量>=1,产生订单之后应该将商品数量减1。
1 select amount from product where product_name='XX';
2 update product set amount=amount-1 where product_name='XX';
显然1的做法是是有问题,因为如果1查询出amount为1,但是这时正好其他session也买了该商品并产生了订单,那么amount就变成了0,那么这时第二步再执行就有问题。那么采用lock in share mode可行吗,也是不合理的,因为两个session同时锁定该行记录时,这时两个session再update时必然会产生死锁导致事务回滚。以下是操作范例(按时间顺序)
使用场景一:数据表的状态
如果存在一张表记录一个商品的状态,在订单的变化过程中,订单的状态是不断变化的,而且变化的过程中肯定也会有并发的问题,而且很多时候与其他系统有交互,会存在补偿的情况,所以并发的可能性很大,补偿或者为了增加状态修改的成功可能性,2次改变状态的情况也有,楼主就遇到了这种情况,真操蛋。于是看到有这样的for update写法。
1 update order set status = 1 where product_id = '1';
2 insert order_flow (..............) value (.........)
这样的情况下就有可能订单的状态已经更新完成了,但是补偿这些额外的消息把状态又更新为待处理或者插入了多条流水的情况(多条流水的可能性大,状态的那种可能补偿滞后)。这个时候就可以使用select .... from order where order_id = '1' for update,先锁住要修改状态的表,这样就不会别人操作了,自己先后面把流水插入,然后更新状态,完美。但是加了锁之后性能就很慢了,担心性能影响,而且有可能存在死锁的情况,后面我就修改为流水表中增加一个唯一索引,这样插入流水报错就是已经处理过的记录了。这样就不会存在性能问题。
通过对比,lock in share mode适用于两张表存在业务关系时的一致性要求,for update适用于操作同一张表时的一致性要求。
Mysql的排他锁和共享锁的更多相关文章
- 【问答分享第一弹】MySQL锁总结:MySQL行锁、表锁、排他锁、共享锁的特点
大家好,我是小于哥哈.前几天能分享了第一期面试题,MySQL 中有哪几种锁 和 这些锁各有哪些特点 ,这道面试题是经常会被问到的一个面试题,大家反馈的都挺不错的.今天特此来总结一下. 首发于公众号[终 ...
- [数据库事务与锁]详解六: MySQL中的共享锁与排他锁
注明: 本文转载自http://www.hollischuang.com/archives/923 在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大 ...
- mysql共享锁与排他锁
mysql锁机制分为表级锁和行级锁,本文就和大家分享一下我对mysql中行级锁中的共享锁与排他锁进行分享交流. 共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能 ...
- 【数据库】MySQL中的共享锁与排他锁
转载:http://www.hollischuang.com/archives/923 在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大大减少数据库 ...
- 【转】MySQL中的共享锁与排他锁
在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大大减少数据库操作的冲突.行级锁分为共享锁和排他锁两种,本文将详细介绍共享锁及排他锁的概念.使用方式及 ...
- MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性
作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...
- 转 MySQL中的共享锁与排他锁
原文链接在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大大减少数据库操作的冲突.行级锁分为共享锁和排他锁两种,本文将详细介绍共享锁及排他锁的概念.使 ...
- MySQL中的共享锁与排他锁
MySQL中的共享锁与排他锁 在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大大减少数据库操作的冲突.行级锁分为共享锁和排他锁两种,本文将详细介绍共 ...
- Mysql的共享锁和排他锁(转载)
mysql锁机制分为表级锁和行级锁,本文就和大家分享一下我对mysql中行级锁中的共享锁与排他锁进行分享交流. 共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能 ...
随机推荐
- 在Intellij IDEA中使用Debug
Debug用来追踪代码的运行流程,通常在程序运行过程中出现异常,启用Debug模式可以分析定位异常发生的位置,以及在运行过程中参数的变化.通常我们也可以启用Debug模式来跟踪代码的运行流程去学习三方 ...
- hover用法实例
//hover,鼠标移入移出的另一种用法 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" &qu ...
- 获取ip地址及城市信息
大家好,今天给大家分享的是一个简单的知识获取登录用户的ip地址及城市信息,lz是一个小白,如果有哪些错误的地方 欢迎大家指出 东西很简单,直接上代码 [HttpPost] public string ...
- hashlib使用时出现: Unicode-objects must be encoded before hashing
# hashlib.md5(data)函数中,data参数的类型应该是bytes# hash前必须把数据转换成bytes类型>>> from hashlib import md5 F ...
- java内存区域分析及java对象的创建
java虚拟机在执行java程序的过程中会将它管理的内存区域加分为若干个的不同的数据区域. 主要包括以下几个运行时数据区域,这里就只介绍经常会用到的 1:java虚拟机栈:我们常说的堆栈,栈就是指的j ...
- Promise的用法
promise.then().promise.catch().Promise.all()... Promise 构造函数接受一个函数作为参数,该函数的2个参数分别是 resolve 和 reject. ...
- oop作业二—circle
oop作业-circle 题目描述 编写一个程序,要求根据给定的圆的半径求圆的面积,并将求得的结果打印出来. 要求: 输入输出采用cin和cout. 建立一个工程,将程序写成两个.cpp和一个.h的形 ...
- 【2017集美大学1412软工实践_助教博客】团队作业9——测试与发布(Beta版本)
题目 团队作业9--测试与发布(Beta版本)(http://www.cnblogs.com/happyzm/p/6917253.html) 团队作业9-1 测试与发布成绩 分值 1 0.5 0.5 ...
- 团队作业8——第二次项目冲刺(Beta阶段)5.25
1.当天站立式会议照片 会议内容: 本次会议为第六次会议 本次会议在陆大楼3楼召开,本次会议内容: ①:检查总结上次任务完成情况 ②:安排今天的分工 ③:对昨天的问题进行讨论 ④:遇到困难,及时群里反 ...
- 201521123076 《Java程序设计》第7周学习总结
1. 本周学习总结 2. 书面作业 Q1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 A:先上源代码: public boolean contains(Obje ...