mysql表中的各种锁
mysql中的锁机制大致比较的简单。而且不同的引擎支持的锁也是不一样的。
mysql常见的按照粒度分有三种锁,分别是:
1.表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
2.行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
3.页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
下面会介绍一下以上的三种锁。
通常锁会分为读锁和写锁两种类别。
1.其中一个进程占用读锁后,加了读锁的这张表不能执行任何的update,insert的操作。但可以被其他的进程读取,也就是可以执行select操作。所以也叫共享锁。
2.一个进程占用一张表的写锁后,该进程可以执行所有的CRUD的操作。而其他进程不能查询和操作这张表,所以也叫排他锁。
表级锁
在MyISAM引擎中,我们只可以使用表级锁。
表级锁又有两种结构:表共享锁(Table Read Lock)和表独占写锁(Table Write Lock)
1.表共享锁是指对一张表进行读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对该表的写请求。
2.表独占写锁是指对表进行写操作时,不允许其他用户对同一张表进行写或者读的操作。
也就是说当一个线程获得一个表的写锁时,只有该线程可以对该表进行操作。其他线程的操作都会被阻塞,直到锁被释放。
如何加表锁
在MySQL中,MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预。
当有些场景需要手动显式的加锁时,利用LOCK TABLE的命令即可。释放锁的命令是unlock tables
MyISAM锁调度
MyISAM存储引擎的读和写锁是互斥,读操作是串行的。所以当一个进程请求某个MyISAM表的读锁,同时另一个进程也请求同一表的写锁时,这种情况下,写进程会先获得锁而且即使读进程先请求先到锁等待队列,写请求后到,写锁也会插到读请求之前执行。这是因为MySQL认为写请求一般比读请求重要。这也正是MyISAM表不太适合于有大量更新操作和查询操作应用的原因,因为大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。
行锁以及InnoDB锁的问题
InnoDB与MyISAM的最大不同有两点:一是支持事务;二是采用了行级锁。
事务事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。有以下四种特性:
1.原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
2.一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
3.隔离性:隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行 相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆, 必须串行化或序列化请 求,使得在同一时间仅有一个请求用于同一数据。
4.持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
InnoDB的锁的模式
行锁
InnoDB的行锁有下面两种模式
1.共享锁:允许一个事务去读一行数据,阻止其他事务获得相同数据集的排他锁。
2.排他锁:允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。
行锁的操作级别是行,所以如果我们对一行进行更新,其他进程更新别的行是不会受影响的。
行锁的粒度更细,所以开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
除此之外,InnoDB还实现了两种表锁,来实现多粒度锁机制。叫做意向锁
1.意向共享锁:事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
2.意向排他锁:事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
InnoDB实现锁
和MyISAM类似,对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及的数据集加排他锁。对于普通SELECT语句,InnoDB会自动给涉及数据集加共享锁。
InnoDB行锁是通过索引上的索引项来实现的,只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!
另外在InnoDB中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁。
总结
事务和行锁往往是我们选择InnoDB还是MyISAM的关键所在。同时MyISAM由于锁都是一次性获得的,所以不会出现死锁的情况。而InnoDB则可能会发生死锁的情况。
下一步需要解决的问题
上面所讲的锁结构只是大致粗略的介绍。其实不同的隔离级别,锁的情况也是不一样的。针对隔离级别也会有间隙锁的存在。间隙锁也会导致死锁的发生。间隙锁,死锁的发生,MyISAM的并发锁机制,InnoDB加索引以及快照读和当前读的锁机制问题下次解决吧。
参考链接:
https://www.cnblogs.com/rjzheng/p/9950951.html
https://www.cnblogs.com/chenqionghe/p/4845693.html