Mysql中各种锁的理解
一:引言--为什么mysql
提供了锁
最近看到了mysql有行锁和表锁两个概念,越想越疑惑。为什么mysql要提供锁机制,而且这种机制不是一个摆设,还有很多人在用。在现代数据库里几乎有事务机制,
ACID
的机制应该能解决并发调度的问题了,为什么还要主动加锁呢?
二:MySQL的事务机制
理解MySql事务隔离机制、锁以及各种锁协议:https://blog.csdn.net/gklifg/article/details/38752691
数据库的acid属性
原性性(Actomicity)
:事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
一致性(Consistent)
:在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
隔离性(Isolation)
:数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
持久性(Durable)
:事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
事务并发调度的问题
脏读(dirty read)
:A事务读取B事务尚未提交的更改数据,并在这个数据基础上操作。如果B事务回滚,那么A事务读到的数据根本不是合法的,称为脏读。在oracle中,由于有version控制,不会出现脏读。
不可重复读(unrepeatable read)
:A事务读取了B事务已经提交的更改(或删除)数据。比如A事务第一次读取数据,然后B事务更改该数据并提交,A事务再次读取数据,两次读取的数据不一样。
幻读(phantom read)
:A事务读取了B事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。这两种情况对策是不一样的,对于不可重复读,只需要采取行级锁防止该记录数据被更改或删除,然而对于幻读必须加表级锁,防止在这个表中新增一条数据。
第一类丢失更新
:A事务撤销时,把已提交的B事务的数据覆盖掉。
第二类丢失更新
:A事务提交时,把已提交的B事务的数据覆盖掉。
三: MySQL
的行锁和表锁
表级锁
:每次操作锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁
:每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高;
页面锁
:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
MySQL
中我们可以在select
语句最后加FOR UPDATE
来对所查询的行加锁.
通过使用for update
可以对数据加写锁
必须在begin/commit
或者autocommit=0
的情况下
如果where条件中只用到索引项,则加的是行锁;否则加的是表锁。
MySQL
中的乐观锁和悲观锁
悲观锁(Pessimistic Concurrency Control,PCC)
:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。至于怎么加锁,加锁的范围也没讲。
乐观锁(Optimistic Concurrency Control,OCC)
:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。也没具体指定怎么检查。
参考文献
mysql的锁--行锁,表锁,乐观锁,悲观锁:https://www.cnblogs.com/deliver/p/5730616.html
mysql for update语法实现行锁:http://blog.techbeta.me/2014/11/mysql-for-update/