事务

概念

事务是一系列数据库操作的集合。

特性(ACID)

atomicity:原子性

即整个数据库事务是不可分割的工作单位,即事务中的操作要么全部执行成功,才算成功,只要有一个操作没有成功,就不算成功,就撤销所有已经执行的操作,数据库状态回退到执行事务前的状态。

consistency:一致性

即数据库从一种状态变为另一种一致的状态,在事务开启之前和事务结束以后,数据库的完整性约束没有被破坏。

isolation:隔离性

一个事务的影响在该事务提交之前对其他事务是不可见的。

durability:持久性

事务一旦提交,其结果就是永久性的。

事务的实现

隔离性由锁实现,原子性,一致性,持久性通过数据库的redo和undo来完成。

redo:

在InnoDB存储引擎中,事务日志通过重做(redo)日志文件和InnoDB存储引擎的日志缓冲(InnoDB Log Buffer)来实现。当事务开始时,会记录该事务的一个LSN(Log Sequence Number 日志序列号),当事务执行时,会往InnoDB存储引擎的日志缓冲里插入日志事务,当事务提交时,必须将InnoDB存储引擎的日志缓冲写入磁盘。先写日志,再写数据的方式,又称预写日志方式。InnoDB存储引擎通过预写日志的方式来保证事务的完整性,这意味着,磁盘上的数据页和内存缓冲池中的页是不同步的,对于内存缓冲池中页的修改,先写入重做日志文件,然后再写入磁盘。

undo:

与undo相反,对于数据库进行修改时,数据库不但会产生redo,还会产生undo,即执行的事务或语句失败或使用回滚语句,就可以利用undo信息将数据回滚到修改之前的样子。redo存放在重做日志文件中,undo存放在数据库内部的一个特殊段中,称为undo段,undo段位置位于共享空间表内。

事务控制

MySQL命令行的默认设置下,事务是自动提交的,即执行完SQL语句后会马上执行COMMIT操作;在其他情况下,事务的开启需要相关的设置,可以使用BEGIN,START TRANSACTION;禁用当前会话的自动提交,可以执行SET AUTOCOMMIT=0.

事务控制语句:

START TRANSACTION | BEGIN :用于开启事务;

COMMIT:提交事务,也可以写为COMMIT WORK,都是用来提交事务,不同之处在于,COMMIT WORK用来控制事务结束后的行为,是CHAIN还是RELEASE的,可通过参数 completion_type来进行控制,默认情况下为0,表示没有任何操作,在这种情况下,COMMIT和COMMIT WORK是完全等价的。当completion_type的值为1时,COMMIT WORK等同于COMMIT AND CHANIN,表示马上开启一个相同隔离级别的事务。当completion_type的值为2时,COMMIT WORK等同于COMMIT AND RELEASE即事务提交之后会自动断开与服务器的连接。

ROLLBACK:用于回滚事务;

SAVEPOINT identifier:SAVEPOINT允许你在事务中创建一个保存点,一个事务中可以由多个SAVEPOINT;

RELEASE SAVEPOINT indentifier:删除一个事务的保存点;

ROLLBACK TO [SAVEPOINT] indentifier:与SAVEPOINT一起使用,用于回滚到标记点;

SET TRANSACTION:设置事务的隔离级别;

注意:ROLLBACK TO SAVEPOINT,虽然有ROLLBACK,但是它并不是真正的结束一个事务,即使执行了ROLLBACK TO SAVEPOINT,还是需要显式地运行COMMIT或ROLLBACK 命令。

隐式提交的SQL语句:SQL语句会产生一个隐式的提交操作,即执行完这些操作后,会有一个隐式的COMMIT操作;DDL语句,用来隐式的修改mysql架构的操作;管理语句。

事务的隔离级别

SQL标准定义的四个隔离级别为:READ UNCOMMITTED ,READ COMMITTED , REPEATABLE READ , SERIALIZABLE。

InnoDB存储引擎默认的支持的隔离级别是REPEATABLE READ,但与标准SQL不同的是,InnoDB存储引擎在REPEATABLE READ的事务隔离级别下,使用Next-Key Lock锁算法。隔离级别越低,事务请求的锁越少,大多数数据库的事务隔离级别是READ COMMITEED。

在InnoDB存储引擎中,可以使用以下方式设置当前会话或全局的事务隔离级别:

SET [GLOBAL | SESSION ] TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITEED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}

在MySQL库启动时设置事务的默认级别,需要修改MySQL的配置文件,在[mysqld]中添加如下:

transaction-isolation = READ-COMMITTED

查看当前会话的事务隔离级别:

SELECT @@tx_isolation;(适用旧版本)

SELECT @@transaction_isolation;(适应新版本)

查看全局的事务隔离级别:

SELECT @@global.tx_isolation;(适用旧版本)

SELECT @@global.transaction_isolation;(适用新版本)

在SERIALIABLE的事务隔离级别下,InnoDB存储引擎会对每个SELECT语句后自动加上LOCK IN SHARE MODE,即每个读取操作加一个共享锁,以为InnoDB存储引擎在REPEATABLE READ隔离级别下就已经可以达到3的隔离,所以一般不在本地事务中使用SERIALIABLE的隔离级别,SERIALIABLE的事务隔离级别主要用于InnoDB存储引擎的分布式事务。

不好的事务习惯

⑴循环中提交事务

⑵使用自动提交,可以通过set autocommit=0;来改变自动提交的方式。

⑵使用自动回滚。

 

参考《MySQL技术内幕 InnoDB存储引擎》   姜承尧著 ,,  建议亲自读此书,加深理解。