阅读 94
MYSQL实战: 事务隔离(一)

MYSQL实战: 事务隔离(一)

说到MYSQL事务我们肯定想到的就是ACID(Atomicity Consistency Isolation Durability),原子性、一致性、隔离性、持久性。不管是原子性还是隔离性和持久性目的都是为了保证数据最终一致性。

什么是事务?

事务是一组数据库操作,要么同时成功,要么同时失败。在MYSQL中事务在执行引擎实现,MYSIAM引擎没有实现事务,也就是没有事务,这也是INNODB逐渐取代MYSIAM原因之一。

事务隔离性和隔离级别

当数据库在同时执行多个事务时候,可能就会出现脏读,不可重复读,幻读问题。而MYSQL为了解决这些问题,提供了四个隔离级别:读未提交,读已提交,可重复读,串行化。他们的隔离级别依次递增,而执行效率依次递减,所以隔离级别越高,执行效率越低。MYSQL默认隔离级别是可重复读,下面是每个隔离级别解释:

  • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读已提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
  • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

当有A、B两个事务,同时开始执行事务,事务B修改值,事务A分别获取V1、V2、V3如下图,不同隔离级别会看到怎样的变化?

image.png

当事务处于读未提交级别下,V1、V2、V3都能查询为2,因为事务B修改的值其他事务马上都能看到。

当事务处于读已提交级别下,V1为1,V2、V3为2,因为事务B修改的值,需要等待事务提交完成后,才能被其他事务看到。

当事务处于可重复读级别下,V1、V2为1,V3为2,因为事务A在没有提交之前,看到V值都会保持不变,只有当前事务提交后,才会看到事务B修改的值。

当事务处于串行化级别下,V1、V2为1,V3为2,因为事务B修改值的时候,有读锁,需要等待事务A提交后才能修改值。

在实现上,MYSQL在读已提交和可重复读级别下,创建一致性读视图,读未提交在每个sql执行时候创建视图,而可重复读在事务开始时候创建视图。读未提交是没有视图概念,直接返回最新一条记录,串行化是通过读写锁来实现隔离也不需要视图。

我们可以通过show variables like 'transaction_isolation';来查询当前MYSQL隔离级别,如下图:

image.png

事务隔离的实现

在可重复读级别下,MYSQL每条数据更新时候都会同时记录一条回滚操作。每个更新记录最新值可以通过回滚操作恢复之前值,同时不同时刻启动事务都会有不同read-view,如下图:

image.png

在视图 A、B、C 里面,这一个记录的值分别是 1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于 read-view A,要得到 1,就必须将当前值依次执行图中所有的回滚操作得到。

回滚日志删除契机是什么时候呢?等当前回滚日志没有比read-view更早的时候,在这里也引出为什么不建议使用长事务,因为长事务会保留大量事务之后的回滚日志,导致占用大量存储空间所以为了避免长事务,尽量设置事务自动提交set autocommit=1

启动事务方式:

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。

查询长事务sql:

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

总结:

本文从什么是事务,事务隔离级别以及用例来介绍每个级别下我们看到的不同视图。并且还提到什么是多版本并发控制,为什么不建议长事务,下篇文章将继续介绍事务到底是隔离还是不隔离的。

参考: 极客时间-MySQL实战45讲

文章分类
后端
文章标签