[mysql] 锁机制

前言

  在计算机的世界里锁(lock)是为了协调多个进程或者多个线程并发的访问同一资源而被创造出来的。而在我们的mysql数据库中的锁也是为了解决并发访问同一资源的问题,下面我就来介绍下mysql中的锁的一些知识,如果有什么说的不对的地方,还希望各位大神指正。

 锁的种类

  在mysql数据库中,可以将锁分为3个种类: 表级锁 、 行级锁 、 页级锁 。

表级锁

定义:对整个表进行加锁处理,在你锁定期间,如果你是读锁,其他进程写操作无法对这张表进行操作。如果你是写锁,则其他进程无法对这张表进行操作。

引擎: MyISAM , InnoDB 

优点: 加锁快 、 开销小 、 不会出现死锁 

缺点: 锁定面积大 、 发生冲突的概率高 、 并发度低 

表级锁模式

  •  表共享读锁 :当一个进程对一张表加了读锁,那么其他的进程也可以同时对这张表加读锁,但是不能加写锁。(即多个用户可以同时读取同一张表的数据)
  •  表独占写锁 :当一个进程对一张表加了写锁,那么其他任何进程都不可以加任何锁。

如何添加表级锁

lock tables table_name1 read local,table_name2 read local;
select * from table_name1;
select * from table_name2;
lock tables;

注意:

  •  local 选项,作用是在满足MyISAM表并发插入条件的情况下,允许其他用户在表尾插入记录。
  • 在使用 lock tables 给表显示加锁后,你只能访问显示加锁的那几张表,不能访问未加锁的表。
  • 在使用 lock tables 给表显示加锁后,mysql是一次性加上你想加锁表的所有表的锁,这就保证了不会产生死锁。

MyISAM的锁

并发锁

MyISAM存储引擎中有一个系统变量 concurrent_insert ,这个变量可以控制并发插入的行为,允许的值为(0、1、2)。

  • 当 concurrent_insert=0 时,不允许并发插入。
  • 当 concurrent_insert=1 时,当一个进程在读一张表时,通知可以允许一个进程向该表中插入数据。(默认设置)
  • 当 concurrent_insert=2 时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。

MyISAM锁调度

对于MyISAM的锁调度,我们需要注意的是:

  • 写进程总是币读进程先获得锁,即使是读进程先到达等待队列,写进程后到达,之后mysql也会先调度写进程。

优点:因为MyISAM是共享读锁的,先执行写进程,可以让读进程积累到一定程度,一起读取数据,可以增加并发度

缺点:如果写进程过多,那么会造成读进程一致无法执行,导致等待时间过长

可以通过以下几种方法解决读进程等待时间过长的问题:

  • 修改优先级
SET LOW_PRIORITY_UPDATES=1;
SET LOW_PRIORITY_INSERT=1;
SET LOW_PRIORITY_DELETE=1;
  • 设置 max_write_lock_count 参数,当一个表的读锁达到这个值后,MySQL变暂时将写请求的优先级降低,给读进程一定获得锁的机会。
set max_write_lock_count=10;

 行级锁

定义:对表中的一行进行加锁,其他进程还可以操作这张表的其他行。

引擎: InnoDB 

优点: 锁定面积小 、 发生冲突的概率低 、 并发度高 

缺点: 加锁慢 、 开销大 、 会发生死锁 

行级锁模式

  •  共享锁(s) :允许多个事务去读同一行,当某个事务对该行加共享行锁,则不允许其他事务去加排它锁。
  •  排它锁(X) :当某个事务给某一行加了排它锁,则不允许其他事务给该行加任何锁。
  •  意向共享锁(IS :在加共享锁前,首先需要在表上加该锁。
  •  意向排他锁(IX) :在加排它锁前,首先需要在表上加该锁。

注意以下几点:

  • 意向锁是InnoDB自动加的。
  • 对于 UPDATE 、 DELETE 、 INSERT 语句,InnoDB会自动加排它锁。
  • 对于 SELECT 语句,InnoDB不会加任何锁。可以通过以下语句给记录加共享锁:
select * from table_name where id = xxx lock in share mode;

InnoDB的锁

 行锁实现方式

  InnoDB行锁是通过索引上的索引项来实现的,只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁。

间隙锁

  当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制不是所谓的间隙锁(Next-Key锁)。

什么时候使用表级锁

  1. 更新的行数是表的大部分数据或整张表时
  2. 事务涉及多个表,比较复杂,很可能引起死锁,造成事务大量回滚。

在InnoDB下,使用表锁要注意以下几点:

  1. 可以使用 lock tables 给InnoDB加表级锁,但是这个表级锁不是由InnoDB存储引擎管理的,而是上一层的MySQL Server管理,并且只有满足 autocommit=0 和 innodb_table_lock=1 时,InnoDB层才能知道MySQL加的表锁,MySQL Server才能感知InnoDB加的行锁,这种情况下,InnoDB才能自动识别涉及表级锁的死锁;否则,InnoDB将无法自动检测并且处理这种死锁。
  2. 在用 lock tables 对InnoDB锁时要注意,要将 autocommit 设置为0,否则MySQL不会给表加锁。

页级锁

定义:对表中某行和相邻行进行加锁。这种做法是对表级锁和行级锁的一中折中方案。

引擎:BDB

原文地址:https://www.cnblogs.com/cafebabe-yun/p/10290268.html