实践阅读:一文彻底读懂MySQL事务的四大隔离级别
1、什么是事务?
数据库事务(简称:事务),是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
假如A转账给B 100 元,先从A的账户里扣除 100 元,再在 B 的账户上加上 100 元。如果扣完A的100元后,还没来得及给B加上,银行系统异常了,最后导致A的余额减少了,B的余额却没有增加。所以就需要事务,将A的钱回滚回去,就是这么简单。
2、MySQL事务的四大特性以及实现原理?
事务特性ACID:原子性(Atomicity
)、一致性(Consistency
)、隔离性(Isolation
)、持久性(Durability
)。
- 原子性(Atomicity): 事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行,是一个不可分割的整体。
- 一致性(Consistency): 指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。
- 隔离性(Isolation): 多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。
- 持久性(Durabilily): 表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。
事务ACID特性的实现思想:
原子性:是使用 undo log来实现的,如果事务执行过程中出错或者用户执行了rollback,系统通过undo log日志返回事务开始的状态。
持久性:使用 redo log来实现,只要redo log日志持久化了,当系统崩溃,即可通过redo log把数据恢复。
隔离性:通过锁以及MVCC,使事务相互隔离开。
一致性:通过回滚、恢复,以及并发情况下的隔离性,从而实现一致性。
3、事务并发会存在哪三种问题?
事务并发会引起数据的脏读、不可重复、幻读等问题。
脏读(dirty read) 是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
- 假设现在A的余额是100,事务A正在准备查询Jay的余额
- 这时候,事务B先扣减Jay的余额,扣了10
- 最后A 读到的是扣减后的余额
- 事务A、B交替执行,事务A被事务B干扰到了,因为事务A读取到事务B未提交的数据,这就是脏读。
不可重复读(unrepeatable read) 是指在对于数据库中的某行记录,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,另一个事务修改了数据并提交了。
- 事务A先查询Jay的余额,查到结果是100
- 这时候事务B 对Jay的账户余额进行扣减,扣去10后,提交事务
- 事务A再去查询Jay的账户余额发现变成了90
- 事务A又被事务B干扰到了!在事务A范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读。
幻读 是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行,就像产生幻觉一样,这就是发生了幻读。
- 事务A先查询id大于2的账户记录,得到记录id=2和id=3的两条记录
- 这时候,事务B开启,插入一条id=4的记录,并且提交了
- 事务A再去执行相同的查询,却得到了id=2,3,4的3条记录了。
- 事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读。
不可重复读侧重于修改,幻读侧重于新增或删除(多了或少量行),脏读是一个事务回滚影响另外一个事务。
4、事务的四大隔离级别是什么?
事务隔离就是为了解决上面提到的脏读、不可重复、幻读等问题,MySQL实现了四种类型的隔离级别:
- 读未提交(Read Uncommitted)在本隔离级别,所有事务都可以看到其他未提交事务的执行结果。 本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
- 读已提交(Read Committed)一个事务只能看见已经提交事务所做的改变。可避免脏读的发生
- 可重复读(Repeatable Read)MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,解决了不可重复读的问题。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。
- 串行化(Serializable)通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
5、如何查看和设置事务的隔离级别?
-- 查看当前事务的隔离级别
SELECT @@transaction_isolation;
-- 或者简写
select @@tx_isolation
-- 查询可得到当前默认的事务隔离级别为 REPEATABLE-READ(可重复读)
mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
-- 设置隔离级别
set session transaction isolation level read uncommitted; -- 设置为读未提交
set session transaction isolation level read committed; -- 设置为读已提交
set session transaction isolation level repeatable read; -- 设置为可重复读(默认的)
set session transaction isolation level serializable; --设置为串行化
6、如何设置事务的手动commit提交
-- 查看当前事务的提交状态
mysql> show variables like '%commit%';
+-----------------------------------------+-------+
| Variable_name | Value |
+-----------------------------------------+-------+
| autocommit | ON | -- 默认是开启状态
| binlog_group_commit_sync_delay | 0 |
| binlog_group_commit_sync_no_delay_count | 0 |
| binlog_order_commits | ON |
| innodb_api_bk_commit_interval | 5 |
| innodb_commit_concurrency | 0 |
| innodb_flush_log_at_trx_commit | 1 |
| replication_sender_observe_commit_only | OFF |
| slave_preserve_commit_order | OFF |
+-----------------------------------------+-------+
-- 关闭事务自动提交
SET autocommit = 0; -- 0 关闭 1 开启
或者:
SET autocommit = off -- off 或 on
-- 默认情况下 autocommit = 1,是自动提交事务的。
-- autommit 是 session 级别的,就是当前连接更改了autocommit对其他连接没有影响。
-- 设置 autocommit 之后,本次连接的所有 sql 都是事务的形式,比如每次 commit 提交。
7、开启事务、提交事务、事务回滚的命令是什么?
-- 演示的时候首先设置 SET autocommit = 0; 把提交事务设置为手动提交
-- 开启事务
mysql> begin;
或者:
mysql> start transaction;
-- 提交事务
mysql> commit;
-- 事务回滚
mysql> rollback;
8、MySql隔离级别的实现原理
实现隔离机制的方法主要有两种:
- 读写锁
- 一致性快照读,即 MVCC
MySql使用不同的锁策略(Locking Strategy)/MVCC来实现四种不同的隔离级别。RR、RC的实现原理跟MVCC有关,RU和Serializable跟锁有关。