事务隔离级别
- 读未提交(read uncommitted)
读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。 - 读提交(read committed)
读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。 - 可重复读(repeatable read)
可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据
是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的 - 串行化(serializable)
串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当
出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
事务隔离级别练习
启动两个窗口
准备语句
create database mysql45;
use mysql45;
查看当前的事务隔离级别
mysql> show variables like 'tx_isolation'; # (我电脑是phpstudy自带的mysql版本是5.5。5.7引入了transaction_isolation,所以用show variables like 'transaction_isolation'; )或select @@tx_isolation;
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
既然是 REPEATABLE-READ
所以我先练习的是可重复读。
A表示左边窗口。B表示右边窗口。
读未提交
设置隔离级别的方式set tx_isolation = 'read-uncommitted';
B还没有commit事务的时候,A事务就能查出刚insert 的数据,也能查出update之后的数据。
当B commit之后,当然A查询的结果不变。
读提交
set tx_isolation = 'read-committed';
B未commit即便插入了数据或者更新元数据;A事务查询的结果是一致的。
B commit 之后;A事务查询到了B commit后的结果。
可重复读
set tx_isolation = 'repeatable-read';
B不commit即便插入了数据或者更新元数据;A事务查询的结果是一致的。(这点跟读提交
是相同的)
B commit,A事务查询仍然是一致的。
串行化
set tx_isolation = 'serializable';
A 先操作语句,B会阻塞住。会用到锁。
或者B先操作语句会阻塞住A。
A commit之后,B不在阻塞就查到了提交的数据了。
begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB 表的语句(第一个快照读语句),事务才真正启动。如果你想要马上启动一个事务,可以使用 start transaction with consistent snapshot 这个命令。
“start transaction with consistent snapshot; ”的意思是从这个语句开始,创建一个持续整个事务的一致性快照。所以,在读提交隔离级别下,这个用法就没意义了,等效于普通的 start transaction。
事务的启动方式
不同时刻启动的事务有不同的read-view,对同一条记录操作,会产生多个版本(回滚段),就是数据库的多版本并发控制(MVCC)。
select @@autocommit; # 或show variables like 'autocommit'; 我的默认为开启
- 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语
句是 rollback。 - set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。
建议 autocommit 为1。通过显式语句启动事务。
长事务
长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的
任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就
会导致大量占用存储空间。
除了对回滚段的影响,长事务还占用锁资源,可能拖垮整个库。
制造一个长事务。B窗口begin 执行一条语句。在A中查。
你可以在 information_schema 库的 innodb_trx 这个表中查询长事务。
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60; // 大于60s。
我问了下DBA,他们监控的长事务就是这张表。
有次有一个小伙伴查数据,没提交就放着。
参考资料:
- 《mysql45讲》03 事务隔离:为什么你改了我还看不见?(笔记来源)
- 《mysql tx_isolation》https://blog.csdn.net/u012807459/article/details/52174601
- 《
1~15讲 —丁奇大大,学习笔记 》https://blog.csdn.net/zxcc1314/article/details/84842650 - 《MySQL · 源码分析 · InnoDB的read view,回滚段和purge过程简介》https://yq.aliyun.com/articles/560506