Mysql之事务隔离级别与锁机制

事务概述

数据库一般都会并发执行多个事务,多个事务间可能会并发对相同的一批数据进行增删改查操作,就可能会造成一些事务隔离性问题,例如:脏写、脏读、不可重复读、幻读。

事务的特性

事务(Transaction)是由一系列数据库操作语句组成的一个逻辑单元。事务中的操作要么全部成功执行,要么全部失败回滚,保证数据库的数据一致性和完整性.下面是事务的四大特性:

原子性(Atomicity)
事务中的所有操作要么全部成功,要么全部失败回滚,不会只执行其中的一部分操作。

一致性(Consistency)
事务开始前和结束后,数据库的状态保持一致性,即满足预定义的数据完整性约束。

隔离性(Isolation)
多个事务并发执行时,每个事务的操作都好像在独立执行,相互之间不会影响。

持久性(Durability)
一旦事务提交成功,其对数据库的修改就是永久性的,即使在系统故障的情况下也不会丢失。

事务隔离性问题

脏写(Dirty Write)

// 描述
脏写指的是一个事务修改了另一个事务未提交的数据,导致未提交的数据被覆盖.
// 场景
假设同时开启事务A,B,选择数据表中同一行数据进行修改,
A事务先完成了对数据的修改并提交了事务,之后B事务对同一数据也修改提交。
最终数据库里的数据是事务B修改的数据。覆盖了A之前修改的数据。就造成了脏写。

脏读(Dirty Read)

// 描述
脏读指的是一个事务读取了另一个事务未提交的数据,后续该数据被回滚,导致读取的数据是无效的.
// 场景
事务A更新一条记录并未提交,事务B读取了这条未提交的数据。
事务A回滚了更新,导致事务B读取的数据是无效的.

不可重复读(Non-Repeatable Read)

// 描述
不可重复读指的是一个事务在读取同一条记录的过程中,多次读取的数据不一致。
// 场景
事务A读取一条记录,事务B更新了这条记录并提交。
事务A再次读取同一条记录,发现数据已经发生了变化。

幻读(Phantom Read)

// 描述
幻读指的是一个事务在读取一系列记录的过程中,多次读取的记录数不一致。
幻读类似不可重复读;不可重复读针对查询操作;幻读针对读是插入和删除操作。
// 场景
事务A查询了一批数据的总数,事务B插入了一些新的记录并提交。
事务A再次查询相同的数据,发现记录数发生了变化。

事务隔离级别

不同隔离级别下的问题发生情况:
读未提交(Read Uncommitted):会出现脏写、脏读、不可重复读和幻读问题,因为事务可以读取未提交的数据。

读已提交(Read Committed):会出现脏写、不可重复读和幻读问题,因为事务只能读取已提交的数据,但其他事务可能在事务读取的过程中提交或回滚。

可重复读(Repeatable Read):会出现脏写和幻读问题,因为事务在读取数据期间,其他事务可能插入新数据或更新数据。

串行化(Serializable):可以避免所有并发问题,因为事务之间互相串行执行,但可能导致性能下降。

在这里插入图片描述

// Mysql数据库默认的隔离级别是可重复读。
// 查看当前数据库的事务隔离级别
show variables like 'tx_isolation';
// 设置数据库隔离级别
set tx_isolation='read-uncommitted'; // 读未提交
set tx_isolation='read-committed'; // 读已提交
set tx_isolation='repeatable-read'; // 可重复读
set tx_isolation='serializable'; // 串行化

锁机制

MySQL的锁机制是为了保证并发事务的隔离性和数据完整性而设计的。MySQL支持多种锁类型,可以根据业务需求和事务隔离级别进行灵活选择。

锁分类

乐观锁

乐观锁是指在事务提交时,才检查数据是否被其他事务修改过。在读取数据时不会加锁,而是在更新数据时通过版本号或时间戳等机制检查数据是否过期,若未过期则更新成功,否则回滚.

悲观锁

悲观锁是指在事务读取数据时就对数据进行加锁,避免其他事务对同一数据进行修改.悲观锁常用于数据写操作,防止数据被其他事务并发修改。

读锁

读锁是一种共享锁,多个事务可以同时对同一资源进行读取,但不允许有事务修改数据。

// 添加读锁
select * from T where id=1 lock in share mode;

写锁

写锁是一种排他锁,当一个事务对某资源加写锁后,其他事务不能对该资源进行读或写操作.

// 添加写锁
select * from T where id=1 for update;

行锁

行锁是对单行数据进行加锁,一个事务对某行加锁后,其他事务不能修改该行数据,但可以修改其他行数据. (行锁是一种写锁).

// InnoDB的行锁实际上是针对索引加的锁(在索引对应的索引项上做标记),不是针对整个行记录加的锁。
// 所以查询sql索引不存在时,从行锁升级为表锁,但是只有不可重复读隔离级别才会这样
// 因为不可重复读隔离级别需要解决可重复读或幻读问题,所以在遍历扫描聚集索引记录时,为了防止扫描过的索引被其它事务修改(不可重复读问题) 或 间隙被其它事务插入记录(幻读问题),从而导致数据不一致,所以MySQL的解决方案就是把所有扫描过的索引记录和间隙都锁上.

表锁

表锁是对整个表进行加锁,当一个事务对表加锁后,其他事务不能对该表进行读写操作.表锁一般用于整表操作,适用于对表进行DDL操作等场景.

页锁

页锁是对数据页进行加锁,一个页包含多行数据。只有BDB存储引擎支持页锁.

意向锁

意向锁是一种间接锁,用于在表级别上指示某一行或某一页将要被锁定,以避免不必要的冲突。

假设A事务已经给T表读某行记录增加了行锁,这时B事务要来给T表上表锁,正常B需要遍历整张表看有没有行记录被锁住,
锁住则不能添加表锁,这过程太消耗性能,所以在A事务添加行锁后,同时会给表设置一个标识,这个标识就是意向锁,
这样B事务过来一看有这个标识就说明已经有锁了,避免了锁冲突.

间隙锁

间隙锁是用于在索引范围之间的间隙上设置的锁,用于防止其他事务在索引范围内插入新行.

// 间隙锁是在可重复读隔离级别下才会生效
// 下图表中的间隙为(id为主键):
(3,10)(10,30)(30,50)(50,100)(100,+)
// 举例:
// 开启事务A -> 执行sql1
// begin;
// select * from user where id = 7 for update;

// 开启事务B -> 执行sql2
// begin;
// insert user(id, name, age, job, skill) VALUES (7,'宇智波斑',100,'SSS','轮回眼');

// -> 会发现sql2一直被堵塞,直到事物A提交后,sql2才执行成功.

在这里插入图片描述
Mysql默认级别是repeatable-read,有幻读问题,间隙锁是可以解决部分幻读问题的。

临键锁

临键锁是行锁和间隙锁的结合.

锁等待分析

// 执行查看所状态
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:从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits: 系统启动后到现在总共等待的次数

//  查看INFORMATION_SCHEMA系统库锁相关数据表
//  查看事务
select * from INFORMATION_SCHEMA.INNODB_TRX;
// 查看锁,8.0之后需要换成这张表performance_schema.data_locks
select * from INFORMATION_SCHEMA.INNODB_LOCKS;  
// 查看锁等待,8.0之后需要换成这张表performance_schema.data_lock_waits
select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;  

// 释放锁,trx_mysql_thread_id可以从INNODB_TRX表里查看到
kill trx_mysql_thread_id
// 查看近期死锁日志信息
show engine innodb status;

总结

隔离级别决定了事务之间的隔离程度,不同隔离级别对应不同的并发控制方式,可以根据业务需求选择合适的隔离级别。锁机制则是实现隔离级别的具体手段,悲观锁适用于并发写较多的场景,而乐观锁适用于并发写较少的场景。在实际应用中,需要根据业务场景和性能需求选择合适的隔离级别和锁机制,以保证数据的一致性和并发性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值