一、SQL事务
事务是确保数据库一致的机制,尤其是发生错误或者服务器崩溃的情况下确保数据库一致的机制。
事务的特性:ACID, 即原子性、一致性、隔离性、持久性
原子性:一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其
中的一部分操作,这就是事务的原子性。
一致性:数据库总是从一个一致性的状态转换到另外一个一致性的状态。
隔离性:通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。
持久性:一旦事务提交,则其所做的修改就会永久保存到数据库中。
隔离级别:在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。(每种存储引擎实现的隔离级别不尽相同)。
四种隔离级别:
READ UNCOMMITTED(未提交读):在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读。
READ COMMITTED(T提交读):大多数数据库系统的默认隔离级别是READ COMMITTED(但mysql不是)。一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也叫做不可重复读,因为两次执行同样的查询,可能会得到不一样的结果。
REPEATABLE READ(可重复读):REPEATABLE READ 解决了脏读的问题,该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的纪录,当之前的事务再次读取该范围的记录时,会产生幻行。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。可重复读是MYSQL的默认隔离级别。
SERIALIZABLE(可串行化):SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。
隔离级别 |
脏读可能性 |
不可重复读可能性 |
幻读可能性 |
加锁读 |
RU | Y |
Y |
Y |
N |
RC |
N |
Y |
Y |
N |
RR |
N |
N |
Y |
N |
S |
N |
N |
N |
Y |
二、MySQL中的事务
MySQL提供了两种事务型的存储引擎:InnoDB 和 NDB Cluster。另外还有一些第三方存储引擎也支持事务,比较知名的包括XtraDB 和 PBXT。
MySQL能够识别所有的4个ANSI隔离级别,InnoDB引擎也支持所有的隔离级别。MySQL服务器层不管理事务,事务是由下层的存储引擎实现的。
事务处理语句
(1)查询mysql事务隔离级别
1、查看当前会话隔离级别 select @@tx_isolation;
2、查看系统当前隔离级别 select @@global.tx_isolation;
3、设置当前会话隔离级别 set session transaction isolation level repeatable read;
4、设置系统当前隔离级别 set global transaction isolation level repeatable read;
5、命令行,开始事务时 set autocommit=0; 或者start transaction; 或者 begin;
(2)MySQL事务处理只要有两种方法
1、用BEGIN(或START TRANSACTION),ROLLBACK,COMMIT来实现
-
BEGIN开始一个事务
-
ROLLBACK事务回滚
-
COMMIT事务确认
2、直接用SET来改变MySQL的自动提交模式:
-
SET AUTOCOMMIT=0 禁止自动提交
-
SET AUTOCOMMIT=1 开启自动提交
-
ROLLBACK事务回滚
-
COMMIT事务确认
3、两种方式的区别: 如果只是对某些语句需要进行事务控制,则使用 START TRANSACTION 语句开始一个事务比较方便,这样事务结束之后可以自动回到自动提交的方式,如果希望所有事务都不是自动提交的,那么通过修改 AUTOCOMMIT 来控制事务比较方便,这样不用在每个事务开始的时候再执行 START TRANSACTION 语句。
三、多版本并发控制(MVCC)
(1)MVCC定义:
MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只是锁定必要的行。MVCC的实现,是通过保存数据在某个时间点的快照来实现的。
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。下面看一下REPEATABLE READ 隔离级别下,MVCC具体如何操作的。
SELECT:
Innodb会根据以下两个条件检查每行记录:
a、Innodb只查找版本小于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
b、 行的删除版本号要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除。
只有符合上述两个条件的记录,才能返回作为查询结果。
INSERT:
Innodb为新插入的每一行保存当前系统版本号作为行版本号。
UPDATE:
Innodb为插入一行新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
* 保存这两个额外的系统版本号,使大多数读操作都可以不用加锁,这样设计使得读数据操作很简单,性能很好,并且也能保证只会读到符合标准的行。不足之处是每行记录都需要额外的存储空间,需要做更多的检查工作,以及一些额外维护工作。
MVCC只在REPEATABLE READ和READ COMMITTED两个隔离级别下工作。
(2) MVCC在不同隔离级别是怎么工作的
1)可重复读隔离级别
begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB表的语句事务才真正启动。如果想要马上启动一个事务,可以使用start transaction with consistent snapshot这个命令。begin/start transaction 启动方式,一致性视图是在执行第一个读语句时创建的;第二种启动方式,一致性视图是在执行start transaction with consistent snapshot时创建的。之后事务里的其他查询都共用这个一致性视图。
对于一个事务视图来说,除了自己的更新总是可见的,是否可见有三种情况:
-
版本未提交,不可见;
-
版本已提交,但是是在视图创建后提交的,不可见;
-
版本已提交,而且是在视图创建前提交的,可见。
一致性读:事务A不论在什么时候查询,看到的这行数据的结果都是一致的,通过一致性视图读取。
当前读:总是读取已经提交完成的最新版本。
一致性读和当前读的应用:
一致性读:可重复读的核心就是一致性读,因此在事务读取数据时,用的是一致性读。
当前读: 1、事务更新数据的时候,只能用当前读,如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。2、select 语句如果加锁,也是当 前读。
2)读提交隔离级别
在读提交隔离级别下,start transaction with consistent snapshot的用法没有任何意义,等效于普通的start transaction。每一个语句执行前都会重新算出一个新的视图。