mysql悲观锁原理详解
(2018-03-02 17:26:13)
标签:
悲观锁mysql |
分类: 数据库 |
mysql中的锁概念
mysql已经成为大家日常数据存储的最常用平台,但随着业务量和访问量的上涨,会出现并发访问等场景,如果处理不好并发问题的话会带来严重困扰。下面介绍一下如何通过mysql的悲观锁来解决因并发访问出现的种种数据不一致问题。
为什么需要锁
锁类型
锁定方式
- 行锁(Record Lock):锁直接加在索引记录上面。
- 间隙锁(Gap Lock):锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
- Next-Key Lock:行锁与间隙锁组合起来用就叫做Next-Key Lock。
锁的实现
- 在可重复读级别下,InnoDB以Next-Key Lock的方式对索引加锁;在读已提交级别下,InnoDB以Index-Record Lock的方式对索引加锁。
- 被加锁的索引如果不是聚族索引,那被锁的索引所指向的聚族索引以及其它指向相同聚族索引的索引也会被加锁。
- SELECT * FROM ... LOCK IN SHARE MODE对索引加共享锁;SELECT * FROM ... FOR UPDATE对索引加排他锁。
- SELECT * FROM ... 是非阻塞式读,(除Serializable级别)不会对索引加锁。在读已提交级别下,总是查询记录的最新、有效的版本;在可重复读级别下,会记住第一次查询时的版本,之后的查询会基于该版本。例外的情况是在串行化级别,这时会以Next-Key Lock的方式对索引加共享锁。
- UPDATE ... WHERE 与DELETE ... WHERE对索引加排他锁。
- INSERT INTO ... 以Index-Record Lock的方式对索引加排他锁
悲观锁原理详解
什么是悲观锁
悲观锁处理流程
- 在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)
- 如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常
- 如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了
- 其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常
mysql悲观锁实现
悲观锁使用的示例代码如下:
- 开始事务。begin;/begin work;/start transaction; (三者选一即可)
- 查询商品信息。select status from item where id=1 for update;
- 插入订单数据。insert into order (id,item_id) values (null,1);
- 修改商品状态。update item set status=2;
- 事务提交。commit;/commit work;(二选一即可)
select…for update
悲观锁优点
- 悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。
- 悲观锁基于DB层面实现,对业务代码无入侵,使用方便
悲观锁缺点
- 悲观锁适用于可靠的持续性连接,诸如C/S应用。 对于Web应用的HTTP连接,先天不适用
- 锁的使用意味着性能的损耗,在高并发、锁定持续时间长的情况下,尤其严重。 Web应用的性能瓶颈多在数据库处,使用悲观锁,进一步收紧了瓶颈
- 非正常中止情况下的解锁机制,设计和实现起来很麻烦,成本还很高
- 不够严谨的设计下,可能产生莫名其妙的,不易被发现的死锁问题
- 悲观的缺陷是不论是页锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好
结语
悲观锁在特定业务场景下有其独特的使用优势,但在大多数互联网场景中性能问题会严重制约我们技术方案的选择,后面再介绍一种新的数据库并发问题解决方案——乐观锁。