MySQL事务详解

536 阅读3分钟

事务是要保证一组数据库操作要么全部成功,要么全部失败。在mysql中,事务是由数据库引擎层实现的,mysql是支持多引擎的数据库,也就是说并不是所有的引擎都支持事务,比如Mysql原生自带的MyISAM引擎不支持事务,而InnoDB引擎支持事务,这也是InnoDB引擎替代MyISAM的原因之一。

##隔离性和隔离级别

事务的四种特性(ACID Atomicity Consistency Isolation Durability) 即原子性 一致性 隔离性 持久性,这里主要说说隔离性。

###事务的隔离级别有四种:

  • 读未提交: 当前事务做的更改未提交之前能被其他事务查询到
  • 读已提交: 当前事务所做的更改未提交之前,对其他事务是不可见的
  • 可重复读: 当前事务期间所做的任何查询与刚开启事务的查询是一致的, 当然当前事务所做的修改未提交前对其他事务也是不可见的
  • 串行化:数据库有读锁和写锁,当事务开启时,下一个事务只能等待前一个事务释放锁,才能启动。

mysql默认的隔离级别为可重复读,oracle的默认隔离级别为读已提交。
总体来说,每种隔离级别都有自己的使用场景,可根据业务来定,比如下面的例子就需要可重复读这种隔离级别。
假设你现在管理一个银行账户模块,有一个表存入的是每个月月底的余额,另一个表存入的是账单明细表,现在你需要判断当前余额与上月月底的余额差额是否与账单明细表的账单对应上了。所以在你对账的过程中,即使有一笔新的账单记录也不影响你的对账结果。这时使用可重复读就很方便。

##事务隔离的实现

在实现上数据库会创建一个视图,数据的访问以视图的逻辑结果为准

  • 读未提交: 直接返回记录上的最新值,没有视图的概念
  • 读已提交: 视图是在每个sql开始执行的时候创建
  • 可重复读: 事务启动时创建一个视图,整个事务存在期间都用这个视图
  • 串行化: 用加锁的方式来实现串行化访问

在mysql中每条记录的更新都会同时记录下回滚操作,记录上的最新值通过回滚操作能还原到更新前的状态,假设一个值从1依次被改成了2,3,4,那么就会依次有三条回滚记录,如图所示

在不同时刻启动的事务会有不同的read-view,如图所示,在read-viewA、read-viewB、read-viewC中对应的值分别为1、2、4,同一条记录在数据库中可能存在多个版本,就是数据库的多版本并发控制(MVCC)
即使现在有一个事务在对该值进行修改,将4修改成6,对其他事务中基于的视图都没有影响