MySQL锁机制

Mysql为了解决并发、数据安全的问题,使用了锁机制。

1. 锁分类(按锁的粒度分类)

表级锁

MySQL中锁定粒度最大的一种锁,对当前操作的整张表加锁!

特点:开销小,加锁快,不会死锁。锁定粒度大,锁冲突概率高,并发度低

myisam 和 innodb 都支持表锁

行级锁

MySQL中锁定粒度最小的一种锁,只针对当前操作的行加锁

特点:开销大,加锁慢,会出现死锁。锁冲突概率低,并发度高。

InnoDB支持的行级锁,包括以下几种:(锁算法,锁机制)

Record Lock: 对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项

Gap Lock: 对索引项之间的“间隙”加锁,锁定记录的范围(对第一条记录前的间隙或最后一条将记录后的间隙加锁),不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行。

Next-key Lock: 锁定索引项本身和索引范围。即Record Lock和Gap Lock的结合。可解决幻读问题。

相关知识点:

1. innodb对于行的查询使用next-key lock

2. Next-locking keying为了解决Phantom Problem幻读问题

3. 当查询的索引含有唯一属性时,将next-key lock降级为record key

4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生

5. 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1


虽然使用行级索具有粒度小、并发度高等特点,但是表级锁有时候也是非常必要的:

事务更新大表中的大部分数据直接使用表级锁效率更高;

事务比较复杂,使用行级索很可能引起死锁导致回滚。

2. 锁分类(按锁的使用性质分类,是否可写分类)


1. 共享锁(S锁,Share Locks,读锁)

其他用户可以并发读取数据,但任何事务都不能获取数据上的排他锁(不能修改),直到已释放所有共享锁。

eg. select ... lock in share mode

2. 排他锁(X锁,Exclusive Locks,写锁)

允许持有排他锁的事务读写数据,阻止其他事务获取该资源的共享锁和排他锁

eg. select ... for update

        delete, insert, update 

三 另外两个表级锁:IS和IX

当一个事务需要给自己需要的某个资源加锁的时候,如果遇到一个共享锁正锁定着自己需要的资源的时候,自己可以再加一个共享锁,不过不能加排他锁。但是,如果遇到自己需要锁定的资源已经被一个排他锁占有之后,则只能等待该锁定释放资源之后自己才能获取锁定资源并添加自己的锁定。

而意向锁的作用就是当一个事务在需要获取资源锁定的时候,如果遇到自己需要的资源已经被排他锁占用的时候,该事务可以需要锁定行的表上面添加一个合适的意向锁。如果自己需要一个共享锁,那么就在表上面添加一个意向共享锁。而如果自己需要的是某行(或者某些行)上面添加一个排他锁的话,则先在表上面添加一个意向排他锁。意向共享锁可以同时并存多个,但是意向排他锁同时只能有一个存在。

InnoDB另外的两个表级锁:

3. 意向共享锁(IS): 表示事务准备给数据行记入共享锁,事务在一个数据行加共享锁前必须先取得该表的IS锁。

4. 意向排他锁(IX): 表示事务准备给数据行加入排他锁,事务在一个数据行加排他锁前必须先取得该表的IX锁。

注意:

1. 这里的意向锁是表级锁,表示的是一种意向,仅仅表示事务正在读或写某一行记录,在真正加行锁时才会判断是否冲突。意向锁是InnoDB自动加的,不需要用户干预。

2. IX,IS是表级锁,不会和行级的X,S锁发生冲突,只会和表级的X,S发生冲突。

3. 死锁和避免死锁

InnoDB的行级锁是基于索引实现的,如果查询语句为命中任何索引,那么InnoDB会使用表级锁. 此外,InnoDB的行级锁是针对索引加的锁,不针对数据记录,因此即使访问不同行的记录,如果使用了相同的索引键仍然会出现锁冲突,还需要注意的是,在通过

SELECT ...LOCK IN SHARE MODE;

SELECT ...FOR UPDATE;

使用锁的时候,如果表没有定义任何索引,那么InnoDB会创建一个隐藏的聚簇索引并使用这个索引来加记录锁。

此外,不同于MyISAM总是一次性获得所需的全部锁,InnoDB的锁是逐步获得的,当两个事务都需要获得对方持有的锁,导致双方都在等待,这就产生了死锁。 发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个则可以获取锁完成事务,我们可以采取以上方式避免死锁:

1.通过表级锁来减少死锁产生的概率;

2.多个程序尽量约定以相同的顺序访问表(这也是解决并发理论中哲学家就餐问题的一种思路);

3.同一个事务尽可能做到一次锁定所需要的所有资源。

你可能感兴趣的:(MySQL锁机制)