Mysql 事务隔离级别
当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性。
隔离级别
在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,在事务内和事务间的可见性。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。
READ UNCOMMITTED (未提交读/脏读)
未提交读/脏读。 这个级别会导致很多问题,但从性能上来说,并不比其他级别好太多。
READ COMMITTED (提交读/不可重复读)
不可重复读的问题:事务A在执行过程中有两次对变量a的读取,而在这两次读取之间,事务B对a做了修改,就会导致事务A的两次读取出的值不同,这就叫“不可重复读”。
REPEATABLE READ (可重复读)
可重复读是Mysql的默认事务隔离级别
幻读的问题,即:在事务A中两次读取某个范围的记录,在两次读取之间,另一个事务B在该范围插入了新的记录,当事务A再次读取时,会产生幻行。InnoDB存储引擎通过多版本并发控制(MVCC) 解决了幻读的问题。
SERIALIZABLE (可串行化)
它强制事务串行执行(或者它本身就是个单线程的模型,例如Redis)。但在普通的数据库中,串行化会导致大量的加锁和锁竞争问题,从而耗费大量的资源,除非是在非常需要确保数据一致性而可以接受没有并发的情况下,才考虑采用该级别。
Mysql事务的使用方式
Mysql 默认采用自动提交的模式,也就是说,如果不是显式地开启一个事务,则每个查询都会被当作一个事务来执行提交操作,在当前连接中,可以通过设置AUTOCOMMIT变量来启用或禁用自动提交模式。
当AUTOCOMMIT=0时,所有的查询都在一个事务中,直到显式地执行了COMMIT 或 ROLLBACK,该事务才结束。
InnoDB 存储引擎是如何实现可重复读隔离级别的?
InnoDB 通过在每行记录后面保存两个隐藏的列,来实现MVCC,这两个列一个保存了行的创建版本号,一个保存了行的过期版本号,每开始一个新的事务,系统版本号都会自动递增。
事务开始时刻的版本号会作为本次事务的版本号,用来和每行记录的版本号进行比较,具体比较方式如下:
SELECT:
只查找创建版本小于等于当前版本,并且删除版本不存在或大于当前版本的记录
这样能保证本次事务SELECT的行,只读取到在本次事务执行前就存在,或是被本次事务新增的数据。
INSERT:
为新插入的每一行保存当前事务版本号,作为该行的创建版本号
DELETE:
为删除的每一行保存当前事务版本号,作为该行的删除版本号
UPDATE:
插入一行新记录,保存当前事务版本号作为该行创建版本号,并同时保存当前版本号到原来的行作为删除版本号
有这两个版本号的存在,使得大多数读操作不用加锁,这样设计使得读操作很简单,性能良好,并且也保证了只会读取到符合标准的行。但不足之处是需要额外的存储空间,并且需要更多的行检查工作和维护工作。