MySQL事务原理

MySQL事务原理

事务隔离

当数据库上有多个事务同时执行的时候, 就会出现脏读、不可重复读
幻读的问题,为了解决这些问题,引出了事务隔离级别

SQL的事务隔离级别包括:

  • 读未提交(read uncommitted): 一个事务还没提交时,它的修改就被其他事务看到了
  • 读提交(read committed): 一个事务提交之后, 它的变更才能被其他事务看到
  • 可重复读(repeatable read): 一个事务执行过程中看到的数据总是和这个事务在启动之初的数据是一致的
  • 串行化(serializable): 对于同一行记录,会加读锁、写锁。后访问的事务必须等前一个事务完成才能执行

事务隔离的实现

在MySQL中,每一条记录在更新时都会记录一条回滚操作,记录上一次的最新值,通过一次次回滚,可以得到以前的某状态下的值。

数据库用视图记录一条记录某一状态,所以一条记录在系统中就存在多个视图版本,这就是数据库的多版本并发控制(MVCC)

回滚日志在不需要的时候被删除, 当系统里没有视图需要用到这次回滚的时候就会被删除。

视图概念

在MySQL中,有两个“视图”

  1. view。它是一个查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果.创建视图的语法是create view
  2. 另一个是InnoDB在实现MVCC时用到的一致性读视图,即consistent read view,用于支持读提交和可重复读隔离级别的实现
视图在MVCC中是怎么工作的

在可重复读隔离级别下,事务在启动后就记录了“快照”,这个快照是基于整个数据库的。
那这个快照是怎么实现的呢,肯定不是拷贝整个库。

在InnoDB中每个事务都有一个唯一的事务ID,transaction id, 它在事务开始时向InnoDB申请,保证严格的递增。
数据库中的每一行都有多个版本,每次事务在更新数据的时候,都会产生一个新数据版本,并且记录transaction id为row trx_id。同时记录指向旧数据的位置,以便能够拿到旧数据。

"row trx_id"

而这个记录了指向旧数据位置的东西,就是undo log(回滚日志),而且不同版本的数据并不是真实存储在数据库中的,而是更具undo log计算出来的。

因此,可重复读,就是一个事务启动后,访问数据行,如果这个数据行的事务id不在已提交事务id数组中,就往前找,直到找到一个可见的版本。

事务的启动方式

  1. 显示启动事务语句, begin/start transaction。 提交commit,回滚rollback
  2. set autocommit=0 ,关闭线程的自动提交。这意味着每个SQL执行都会开启事务,事务持续直到你主动执行commit或者rollback

不推荐用2,因为如果设置了关闭自动提交,那这次长连接都需要手动提交事务