MySQL数据库 锁机制简介

数据库锁定机制简单来说就是数据库为了保证数据的一致性而使各种共享资源在被并发访问访问变得有序所设计的一种规则。对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能例外。MySQL数据库由于其自身架构的特点,存在多种数据存储引擎,每种存储引擎所针对的应用场景特点都不太一样,为了满足各自特定应用场景的需求,每种存储引擎的锁定机制都是为各自所面对的特定场景而优化设计,所以各存储引擎的锁定机制也有较大区别。

一、MySQL有三种锁的级别:页级、表级、行级。

MyISAM和MEMORY存储引擎采用的是表级锁;

BDB存储引擎采用的是页面锁,但也支持表级锁;

InnoDB存储引擎既支持行级锁,也支持表级锁,但默认情况下是采用行级锁。

MySQL这3种锁的特性可大致归纳如下:

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

二、死锁

死锁是指两个或者两个以上的事务在执行过程中,因争夺资源而造成的一种相互等待的现象。解决死锁最简单的一种方式是超时,即当两个事务相互等待是,当一个等待时间超过设置的某一阀值时,其中一个事务进行回滚,另外一个等待的事务就能继续进行。在InnoDB存储引擎中,参数innodb_lock_wait_timeout用来设置超时时间。

三、MyISAM表级的读写锁

MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)

在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预。

读锁:允许另一个线程对表的数据进行查询,不允许增删改

写锁:不允许另一个线程对标数据的增删改查。

四、InnoDB的锁(行级别和表级别)

InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

InnoDB实现了以下两种类型的行锁

1、  共享锁(S:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。

2、 排他锁(X)允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁

1、 意向共享锁(IS:事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

2、  意向排他锁(IX:事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

 

意向锁是InnoDB自动加的,不需用户干预。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁。

共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。

排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE。

共享锁 Shared (S) Locks

共享锁允许多个transaction同时对一个资源进行读(SELECT)操作,但是不允许其它transaction对 加锁的资源进行修改。读操作完成后,共享锁会被立即释放(除非隔离级别是Read Repeatable或者更高, 或者显式地通过locking hint要求在transaction期间保持这个共享锁)。

排它锁 Exclusive (X) Locks

当一个transaction在一个资源上加上排它锁之后,其它的transaction不能对这个资源进行修改操作以及 读操作(除非隔离级别是Read Uncommitted或者使用了NOLOCK hint,才允许读操作)。