文章目录
- 事务隔离级别
- 解析
- 常用命令
- 查看事务隔离级别设置
- 修改隔离级别
- 隔离级别演示
- Mysql事务操作
- MVCC实现原理
- undo log版本链
- ReadView
- 练习一下
- 案例1
- 案例2
- 问答环节
- 1、Mysql 可重复读到底有没有解决幻读?
事务隔离级别
Mysql的事务隔离级别是由Mysql的各种锁以及MVCC机制来实现的。
不同隔离级别存在的问题:
在Mysql Innodb存储引擎下,RC、RR是基于MVCC(多版本并发控制)进行并发事务控制的。
先来看一个问题,先想一下在不同隔离级别下,事务D读取到的内容是什么?
解析
Undo Log版本链
RC隔离级别时的ReadView:
常用命令
查看事务隔离级别设置
# 查看事务隔离级别 5.7.20 之后
show variables like 'transaction_isolation';
SELECT @@transaction_isolation
# 5.7.20 之后
SELECT @@tx_isolation
show variables like 'tx_isolation'
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
修改隔离级别
完整设置语句
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
案例:设置全局隔离级别为读提交级别。
mysql> set global transaction isolation level read committed;
隔离级别演示
set tx_isolation='read-committed';
BEGAIN;
UPDATE t_user set name = '子涵先生';
COMMIT;
Mysql事务操作
Mysql事务开启有两种方式:
begin
/start transaction
:begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB表的语句,事务才真正启动。start transaction with consistent snapshot
:这个命令可以立即启动一个事务。
InnoDB里面每个事务有一个唯一的事务ID,叫作transaction id。它是在事务开始的时候向InnoDB的事务系统申请的,是按申请顺序严格递增的。
MVCC实现原理
MVCC的实现原理是基于:undolog版本链+Readview。
undo log版本链
- trx_id:事务版本号,自增;
DB_ROLL_PTR
(回滚指针):指向上一个版本的数据。
UBDO_LOG版本链不是立即删除的,Mysql在确保版本链数据不再被“引用”后才会进行删除。
ReadView
ReadView的作用:从版本链中读取数据,数据读取的时候为“快照读”。
补充一下:
- 快照读:普通的select查询语句;
- 当前读:Insert、Update、Delete、Select … for update、Select …lock in share mode。
ReadView的结构:
m_ids
:表示在生成readview时,当前系统中活跃的读写事务id列表;min_trx_id
:表示在生成readview时,当前系统中活跃的读写事务中最小的事务id,也就是m_ids中最小的值;max_trx_id
:表示生成readview时,系统中应该分配给下一个事务的id值;creator_trx_id
:表示生成该readview的事务的事务id。
MVCC中的数据读取规则:
- 优先读取当前事务版本中的数据;
- 否则根据版本链找到
非活跃事务
中的数据。
READ COMMITTED
和REPEATABLE READ
均是基于MVCC实现的,其区别就在于ReadView中的的生成时机:
READ COMMITTED
生成时机是在每次查询时;REPEATABLE READ
是在当前事务开启时创建的。
练习一下
案例1
事务A:
select * from user where user_name ='张三'; -- 张三user_age为50
-- 此时事务B执行一下
select * from user where user_name ='张三'; -- question1:在两种不同的事务隔离级别下,张三user_age为结果为多少?
事务B:
insert into user (user_name,user_age) values ('张三',25);
案例2
事务A:
select * from user where user_name ='张三'; -- 张三user_age为50
-- 此时事务B执行一下
select * from user where user_name ='张三'; -- question1:张三user_age为结果为多少?
update set user_age = 100 where user_name ='张三';
select * from user where user_name ='张三'; -- question2:张三user_age为结果为多少?
事务B:
insert into user (user_name,user_age) values ('张三',25);
问答环节
1、Mysql 可重复读到底有没有解决幻读?
幻读的官网解释:The so-calledphantomproblem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a
SELECT
is executed twice, but returns a row the second time that was not returned the first time, the row is a“phantom”row.
能,但不完全能,遇到当前读
的时候,ReadView会被重新创建,可以读取到其他事务提交后被新增的数据。