MySQL事务


概述

关于事务,有一个经典的例子:

张三转账给李四10块钱,需要两个步骤,第一,张三扣10块钱,第二,李四加10块钱。那么问题来了,如果第二个步骤失败了,那么张三的钱咋办?答案是回滚。

事务到底是什么?

就是在执行N个SQL语句时,要么都成功,不允许出现其中一部分成功,一部分失败的情况。一旦有任意一个SQL失败,那么将已经成功的SQL进行回滚,回到执行之前的状态

在mysql中,常用的存储引擎有InnoDB和MyISAM,其中MyISAM不支持事务,以下讲的事务都是基于InnoDB存储引擎

什么是事务隔离级别呢?

上面的例子只是单个事务执行,如果有多个事务时会发生什么呢?

假设张三扣了10块钱时,还没执行下一步,这时王五给张三打20了块钱,好巧不巧,李四在加10块钱时失败了,张三的账户金额需要回滚,这时候应该回滚到多少钱呢?

回滚了之后,王五如果后续操作也失败了,也要回滚张三的账户,那么就会有两个事物都要回滚张三的余额,这时候数据就错乱了

简单来说,事物隔离级别存在就是为了解决:多个事务在操作同一行数据时,应该怎么处理?

事务隔离级别

标准的SQL设计中,事务隔离级别主要有以下几种:

隔离级别 中文
serializable 串行化
repeatable read 可重复读
read committed 读提交
read uncommitted 读未提交

serializable 串行化

该隔离级别是最严格的隔离级别,当一个启动事务时,将会对要读写的记录加锁,在事务结束之前,其他任务事务都无法对加锁的记录进行任何操作,包括写操作

这意味着数据可以保证绝对无误,不会有任何的污染,但锁带来的就是性能的损失。串行化是性能最低的事务隔离级别

Repeatable Read 可重复读

这是MySQL中InnoDB默认的隔离级别 ,在该隔离级别下,一个事务中,读到数据始终是一样的(前提是自己没有修改它),举个例子:

有一条记录money = 1,事务A启动,读到该记录,然后事务B修改 money=2,并且提交事务,这时事务A再一次读取该记录,发现money仍然等于1。

示意图如下:

repeatable read 可重复读

用一句话来形容该事务隔离级别就是:别的事务怎么样,跟我没关系

Read Committed 读提交

读提交的意思是,可以读到提交的事务。也可以叫做“不可重复读”,这是Oracle数据库的默认事务隔离级别。

再以上面的例子,如果是在Read Committed 隔离级别下,那么事务A第二次读的时候就可以读到money=2,因为事务B已经提交了,提交了就能被读到了

示意图如下:

read committed 读提交

Read Uncommitted 读未提交

该事务隔离级别下,即便是未提交的数据,也能被其他事务给读取到,因此该隔离级别是不安全的,因为未提交的数据,将来可能是要回滚的,也就是说被其他事务读走的数据,可能是错误数据

Read Uncommitted 读未提交

修改事务隔离级别

可以使用以下命令查看当前事务隔离级别:

mysql> show variables like '%tx_isolation%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.01 sec)

PS: 如果是MySQL5.7及以上版本,使用transaction_isolation 替代 tx_isolation

临时修改

set [ global | session ] transaction isolation level Read uncommitted | Read committed | Repeatable | Serializable;

该命令中,globalsession是可选的,含义如下:

  • global:修改全局session隔离级别
  • session:修改当前session隔离级别
  • 不填:仅修改下一个session的隔离级别

例如,将事务隔离级别改为Read committed

set global transaction isolation level Read committed

注意:修改后需要退出再登录才能看到修改的事务隔离级别

永久修改

永久修改需要修改mysql的配置文件,在my.cnf的[mysqld]下加上:

transaction-isolation=Read-Committed

重启服务

脏读与幻读

脏读就是读到了错误的脏数据,在Read Uncommited读未提交的事务隔离级别下可能发生脏读。

例如事务A读到并将money由1修改为2,并且未提交,而此时事务B读到了money=2,接着事务A回滚了,money又回到了1,事务B就错误的读到了脏数据money=2

示意图如下:

脏读

幻读是在多次读的时候得到了不一样的结果,宛如幻觉,举个例子,事务A查询id=1的记录,发现不存在,准备插入id=1这条记录,此时事务B也插入了id=1,导致事务A因主键冲突而操作失败,事务A再次发现,发现id=1的记录不存在啊,那为啥我会主键冲突呢?幻觉?

示意图如下:

幻读

各个事务隔离级别下脏读幻读现象:

事务隔离级别 脏读 幻读
serializable 串行化
Repeatable Read 可重复读
Read Committed 读提交
Read Uncommitted 读未提交
文章作者: 周君
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 周君 !
评论