Author:赵志乾
Date:2018-10-20
Declaration:All Right Reserved!!!
1、锁机制
锁机制主要用于并发操作,来保证数据的一致性,即使的共享资源在被并发访问时,变得有序而强加的一种约束规则。mysql的锁机制亦是如此,只不过它的锁机制是由存储引擎提供的。选择不同的存储引擎,其支持的锁机制也不相同。比如:Innodb存储引擎支持表级锁和行级锁,而MyISAM则只支持表级锁。
表级锁和行级锁各有优缺点,要根据具体的应用场景进行选择。其特点如下:
表级锁:其施加于数据库表上,操作快、开销小,但由于粒度较大,导致锁冲突概率高,并发度相对较低。
行级锁:其施加于数据库表的行记录上,操作慢,开销大,但由于粒度小,导致锁冲突概率低,并发度相对较高。
2、锁类型
Innodb作为mysql最常用的存储引擎,其支持4种类型的锁,包括:读锁(共享锁)、写锁(排他锁)、意向锁和MDL锁。
读锁又可成为共享锁或者S锁,其内含的约束规则为:如果事务A获取了数据行IL的读锁,则事务B获取数据行IL的读锁时,可以顺利进行,即读锁可以被连续多次获取,但如果事务B要获取数据行IL的写锁时,将会被阻塞,直到数据行IL的写锁被释放。共享锁的优点就是能够在保证数据并发访问一致性的前提下,提升并发访问效率。该优点在读多写少的场景下尤为突出。
读锁有两种类型:
1、自动提交模式下的select查询语句,其本身是不加锁的,属于一致性非锁定读。
select * from tbl_usr_info where usr_id=123;
2、显示加锁,即通过下面的sql语句对被读取的行记录或行记录集合加一个读锁。
select * from tbl_usr_info where usr_id=123 lock in share mode;
写锁又可称为排他锁或者X锁,其内含的约束规则为:如果事务A获取了数据行IL的写锁,则事务B获取数据行IL的其他锁时,将会被阻塞。
写锁有两种添加方式:
1、对于增删改的sql语句,其本身会自动对所操作的数据行添加写锁;
update tbl_usr_info set usr_name="zhaozhiqian" where usr_id=1;
2、对于select读取的行记录也可以添加读锁,其方式如下:
select * from tbl_usr_info where usr_id=1 for update;
MDL锁的全称为meta data lock,其内含的约束规则为:会话A中,如果表T上开启了查询事务,其便会自动获得该表的MDL锁,则会话B中的事务在执行DDL语句操作时,便会被阻塞。该锁类型主要是用于保证表中的元数据信息的一致性。
意向锁是一种表级锁,其作用和MDL锁类似,都是为了防止在事务执行过程中,其他事务因执行DDL语句而造成的数据不一致问题,且MDL锁和意向锁多是自动添加的,不需要手动控制。
意向锁又可分为两类:
意向共享锁(IS):在给一个数据行加共享锁前必须先获取该表的IS锁;
意向排他锁(IX):在给一个数据行加排他锁前必须先获取该表的IX锁;
3、锁等待和死锁
锁等待是指事务A要获取的锁已经被事务B占用,此时事务A的执行流程将阻塞,直至事务B释放事务A所需的锁或者出现锁等待超时。其中锁等待超时主要是为了避免事务长时间等待,其等待超时时间可在innodb_lock_wait_timeout中进行控制,单位为秒。
死锁则是锁等待中比较特殊的一种场景,即事务A和事务B相互等待被彼此占用的锁资源。Innodb存储引擎能够自动检测死锁,并在发生死锁时,自动回滚事务。
实际应用中,通常采用以下4中方式来尽可能避免死锁的发生:
1、如果不同的应用程序会并发存取多个表,或者涉及多个行记录时,应尽量约定以相同的顺序访问表,从而降低死锁产生的机率。
2、业务中尽量采用小事务、避免大事务,使得事务得以及时提交或回滚,从而降低死锁机率。
3、同一事务中,尽量做到一次锁定所需要的所有资源,从而降低死锁机率。
4、对于极易产生死锁的部分,可以尝试提升锁粒度,即通过表级锁来降低死锁机率。