逆水行舟 —— MySQL的锁

MySql锁

简单介绍

  • 数据库锁机制简单来说就是数据库为了保证数据的一致性而使各种共享资源在被并发访问时,使得访问有序所设计的一种规则

  • 锁机制是针对存储引擎的,不同的引擎有不同的优化设计

  • MySQL有三种类型的锁定机制:行级锁定、页级锁定、表级锁定

  • MySQL的InnoDB和MyISAM储存引擎最大的区别就是:事务的支持、行级锁的支持

三种锁机制的理解

在上面我们有讲到MySQL有三种锁机制,下面对其进行详细的说明:

行级锁定

  • 对一条数据进行锁定,锁定粒度最小,正是因为如此能够使得程序可以尽可能大的并发访问数据库,提升高并发系统的整体性能有优点就有缺点,虽然在并发处理能力上有较大的优势,但是行级锁的粒度最小,每次获取锁和释放锁都需要额外的消耗,此外行级锁有死锁隐患

页级锁定

  • 页级锁定是MySQL中比较特殊的一种锁定机制,锁定粒度介于行级锁定和表级锁定,也有死锁隐患

表级锁定

  • 直接将整个表锁定,是MySQL中最大粒度的锁定机制,最大的特点是实现逻辑非常简单,带来的系统负面影响最小,获取与释放锁速度都很快,但由于锁定的粒度最大,处理并发需求很弱,但可以消除死锁隐患

可归纳为:

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

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

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

对于表级锁,还有点东西可以叨唠叨唠

MySQL的表级锁有两种模式:表共享读锁、表独占写锁

查看表级锁定争用状态变量: show status like 'table%';

  • table_locks_immediate:产生表级锁定的次数;

  • table_locks_waited:出现表级锁定争用而发生等待的次数;

  

  • 手动增加表锁 : lock table 表名称 read(write),表名称2 read(write),其他;

  • 查询表锁情况:show open tables;

  • 删除表锁:unlock tables;

读锁

还是讲解一下:

  1. 首先我们在第一个连接里面 使用 lock table oyherTest read; 给otherTest表上了一个读锁

  2. 然后我们再当前会话进行查询,可以发现我们可以查询到数据

  3. 在当前连接,当我们想往表中更改数据的时候,发现报错了,如果其他连接想更改数据,会处于等待状态

  4. 当我们使用 unlock tables; 释放所有锁的时候,其他的连接对该表的更改会生效

写锁

InnoDB引擎的锁机制

  1. 大家都知道,我们当前使用的MySQL的默认储存引擎就是InnoDB,下面对其的锁机制进行学习

  2. 共享锁:允许一个事务去读一行,阻止其他事务来获取相同数据集的,是一个排它锁

  3. 排它锁:允许获得该锁的事务更新数据,阻止其他事务获取相同数据集的共享读锁和排他写锁

  4. 对于update、delete、insert语句,InnoDB会自动给涉及数据集加排它锁

  5. 对于普通select语句,InnoDB不会加任何锁,事务可以通过以下语句显示给记录集加共享锁或排它锁

    • 共享锁:select * from table_name where ... lock in share mode;

    • 排它锁:select * from table_name where ... for update;

  6. InnoDB行锁是用过给索引项加锁来实现的,因此InoDB这种行锁实现的特点就意味着,只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将会使用表锁;

InnoDb的行级锁同样分为两种类型:共享锁、排它锁

而在锁定机制的实现过程中为了让行级锁和表级锁共存,InnoDB使用了意向锁,也就有了意向共享/排他锁

  

InnoDb的锁定是通过在指向数据记录的第一个索引键之前和最后一个索引键之后的区间上标记锁定信息,所以select 查询过程中通过范围查询的话,就会锁定整个范围内所有的索引键值,即使这个键值并不存在

演示区域

Innodb所使用的行级锁定争用状态查看:show status like 'innodb_row_lock%';

  

  • Innodb_row_lock_current_waits:当前正在等待锁定的数量;

  • Innodb_row_lock_time:从系统启动到现在锁定总时间长度;

  • Innodb_row_lock_time_avg:每次等待所花平均时间;

  • Innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间;

  • lnnodb_row_lock_waits:系统启动后到现在总共等待的次数;

行锁的基本演示:

在有索引的情况下,是行级锁定  

  

  • 我们依次设置关闭自动提交,这时会话一的连接会获得锁

  • 然后我们在更改表中的数据,在未commit之前,我们在会话二中也对同一行数据进行更改,会处于阻塞状态

  • 会话一commit提交后释放锁,此时处于阻塞状态的会话二也相继完成更改,最后提交

在无索引的情况下升级为表锁

  

  • 在自动提交关闭的情况下继续演示,我们不是用索引更改一条数据

  • 在尚未提交的情况下,我们通过会话二,对表中的其他行数据进行更改,会处于阻塞状态

  • 当会话一提交完成后,会话二相继完成更改操作

至于死锁的话,我就口头表述一下:

  • 在自动提交关闭的情况下,会话一使用索引对表中的一行数据进行了更改,此时为行级锁定,

  • 会话二此时也通过索引对另一条数据发生了更改操作,也是行级锁定

  • 在上面的环境下,会话一相对会话二所操作的数据进行更改,会话二也想对会话一所操作的数据进行更改

  • 在他们双方都没有提交释放锁的前提下,双双等待对方释放锁,至死不休;

猜你喜欢

转载自www.cnblogs.com/msi-chen/p/10897843.html
今日推荐