Mysql锁、事务隔离级别详解

一、MySQL锁

锁是计算机协调多个进程或线程并发访问某一资源的机制。 在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。
很多人在开发过程中,应该注意到很多锁的问题,在数据库中,有时候我们没有给SQL语句加锁,这些SQL语句也正常的运行,那是因为MySQL自动帮我们加了隐式锁,在某些其他特殊情况,可能会需要我们自己主动加锁。

1、锁分类

在MySQL中,锁机制比较简单,并且不同的存储引擎支持不同的锁机制。

  • MyISAM 存储引擎采用表锁。
  • BDB 存储引擎采用页面锁,也支持表锁。
  • InnoDB 存储引擎即支持表锁,也支持行锁,默认使用行锁。

从性能上分为:悲观锁乐观锁
从数据操作类型上分为:读锁写锁。(都属于悲观锁)
读锁(共享锁):针对同一份数据,多个读操作可以同时进行并且不会相互影响
写锁(排他锁):在写操作完成之前,会阻塞其他写锁和读锁。
从数据操作粒度上分为:表锁行锁

1.1 表锁

每次操作锁住整张表,开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

  • 手动增加表锁:lock table 表名称 read(write),表名称2 read(write);
  • 查看表锁:show open tables;
  • 删除表锁:unlock tables;

1)手动增加表读锁


表锁语句

当前session和其他session都可以读该表


Mysql锁、事务隔离级别详解_第1张图片
查询结果

当前session中插入或者更新锁定的表都会报错,其他session插入或更新则会等待


更新结果

2)手动增加表写锁


Mysql锁、事务隔离级别详解_第2张图片
查询结果

更新结果

3)查看表锁情况


Mysql锁、事务隔离级别详解_第3张图片
查看表锁情况

4)删除表锁


Mysql锁、事务隔离级别详解_第4张图片
删除表锁

结论:MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。表锁中读锁会阻塞写,但是不会阻塞读;写锁则会阻塞读和写。

1.2 行锁

每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。
上面说了,MyISAM 只支持表锁,InnoDB可以支持表锁和行锁,但是,InnoDB只有通过索引条件检索数据才使用行级锁,否则,InnoDB也会走表锁。所以说:InnoDB的行锁是基于表索引的。同时,InnoDB 与 MyISAM 引擎的不同之处还有,InnoDB支持事务

1、行锁支持事务

在并发事务中,可能会带来如下问题:

  • 脏读:事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。(针对未提交数据)
  • 不可重复读:事务A读取到了事务B已经提交的修改数据。(针对其他提交前后,读取数据本身的对比)
  • 幻读:事务A读取到了事务B提交的新增数据。(针对其他提交前后,读取数据条数的对比)
  • 更新丢失:当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。

1) 事务的隔离级别
脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数 据库提供一定的事务隔离机制来解决。
事务的隔离级别就是通过锁的机制来实现,锁的应用最终导致不同事务的隔离级别,只不过隐藏了加锁细节,事务的隔离级别有4种:

Mysql锁、事务隔离级别详解_第5张图片
事务隔离级别

数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔 离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。
mysql默认事务隔离级别为:可重复读(REPEATABLE-READ)

查看mysql事务隔离级别:
5.7版本:
show variables like 'tx_isolation';
8.0版本:
show variables like 'transaction_isolation';

2、行锁分析

通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况

show status like '%Innodb_row_lock%'
Mysql锁、事务隔离级别详解_第6张图片
image.png

对各个状态量的说明如下:
Innodb_row_lock_current_waits: 当前正在等待锁定的数量
Innodb_row_lock_time: 从系统启动到现在锁定总时间长度
Innodb_row_lock_time_avg: 每次等待所花平均时间
Innodb_row_lock_time_max: 从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits: 系统启动后到现在总共等待的次数

优化建议:

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
  • 合理设计索引,尽量缩小锁的范围尽可能减少检索条件范围,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行
  • 尽可能低级别事务隔离

你可能感兴趣的:(Mysql锁、事务隔离级别详解)