目录
7.1 概述
7.1.1 ACID
-
原子性:要么都做,要么都不做
-
一致性:数据库从一种一致性状态转变为下一种一致性状态
-
隔离性:每个读写事务的对象对其它事务的操作对象能相互分离,即:该事务提交前对其他事务都不可见
-
持久性:事务一旦提交,其结果就是永久性的
7.1.2 分类
1. 扁平事务
最简单,所有操作都处于同一层次,由begin开始,由commit或者rollback结束,其间操作都是原子的
2. 带有保存点的扁平事务
允许在事务执行过程中回滚到同一事务中较早的一个状态
保存点:通知系统应该记住事务当前的状态,以便当之后发生错误时,事务能回到保存点当时的状态;使用 SAVE WORK
函数建立,通知系统记录当前的处理状态;保存点在事务内部单调递增
当系统发生崩溃时,所有的保存点都将消失。当进行恢复时,事务需要从最开始处重新执行,而不能从最近的一个保存点继续执行
案例:出门旅游
3. 链事务
可视为保存点模式的一种变种。
在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要执行的事务。注意,提交事务操作和开始下一个事务操作将合并为一个原子操作,也就是下一个事务将看到上一个事务的结果。
回滚仅限于当前事务,即只能恢复到最近的一个保存点
4. 嵌套事务(不原生支持)
是一个层次结构框架,由一个顶层事务控制着各个层次的事务
所有子事务都在顶层事务提交后才真正的提交,任意事务的回滚都会引起它的所有子事务的回滚
5. 分布式事务
在分布式环境下运行的扁平事务,需要根据数据所在位置访问网络中的不同节点
案例:银行转账,从一张卡转到另外一张卡
7.2.1 redo
基本概念
-
重做日志缓存和重做日志文件
-
顺序写
-
fsync操作:重做日志缓存 -> 文件系统缓存 -> 文件系统,因此,磁盘的性能决定了事务提交的性能,即数据库性能
-
重做日志刷新到磁盘的策略,事务提交时、master thread每秒操作或者事务提交时,将重做日志写入文件系统缓存
-
与二进制日志(进行POINT IN TIME的恢复及主从复制的建立)的区别
log block
重做日志缓存、重做日志文件都是以块(block)的方式进行保存的,称之为重做日志块(redo log block),每块的大小为512字节。
若一个页中产生的重做日志数量大于512字节,那么需要分割为多个重做日志块进行存储。
由于重做日志块的大小和磁盘扇区大小一致,都是512字节,因此重做日志的写入可以保证原子性,不需要doublewrite技术。
重做日志块的结构:日志块头(12字节)、日志(492字节)、日志块尾(8字节)
重做日志格式
重做日志格式是基于页的,虽然有着不同的重做日志格式(InnoDB 1.2 有51种),但是它们有着通用的头部格式。
通用的头部格式由以下3部分组成:
-
redo_log_type:重做日志的类型
-
space:表空间的ID
-
page_no:页的偏移量
LSN(Log Sequence Number)
日志序列号,占8个字节,并且单调递增,其表示的含义有:
1. 重做日志写入的字节的总量
LSN=1000;事务1写入100字节,LSN=1100;事务2写入200字节,LSN=1300
LSN存在于重做日志和每个页中,在每个页的头部,有一值FIL_PAGE_LSN,记录了该页的LSN,表示该页最后刷新时LSN的大小,可以用来判断页是否需要进行恢复操作,若在页中的LSN=1000,数据库启动时,LSN=1300,并且该事务已经提交,那么需要进行恢复操作,反之,则不需要。
通过show engine innodb status
查看LSN的情况。
LOG
---
Log sequence number 381727521755 -- 当前的LSN
Log flushed up to 381727521755 -- 刷新到重做日志文件的LSN
Pages flushed up to 381727306352 -- 当前最旧的脏页数据对应的LSN
Last checkpoint at 381727304797 -- 刷新到磁盘的LSN
0 pending log flushes, 0 pending chkp writes
11035274 log i/o's done, 0.98 log i/o's/second
2. checkpoint的位置
3. 页的版本
恢复
重做日志记录的是物理日志,因此恢复速度比逻辑日志,如二进制日志,要快很多。
checkpoint机制表示已经刷新到磁盘页上的LSN,因此在恢复过程中仅需要恢复checkpoint开始的日志部分。如,当数据库在checkpoint的LSN为10,000发生宕机,恢复操作仅恢复LSN 10,000 ~ 13,000范围内的日志。
重做日志是幂等的,即:f(f(x)) = f(x)
案例:insert操作
7.2.2 undo
基本概念
可以被重用
作用:
-
回滚
-
MVCC
对数据库进行修改时,不仅会产生redo,还会产生一定量的undo,利用undo信息可以将数据回滚到修改之前的样子。
undo存放在数据库内部的一个特殊段(segment)中,这个段称为undo段,位于共享表空间中。
存储的是逻辑日志,即SQL语句。回滚时,做的是与之前相反的工作,对于每个insert,InnoDB存储引擎会执行一个delete;对于每个delete,会执行一个insert;对于每个update,会执行一个相反的update,将修改前的行放回去。
undo log会产生redo log,也就是undo log的产生会伴随着redo log的产生,这是因为undo log也需要持久性的保护。
存储管理
InnoDB存储引擎有rollback segment,每个回滚段中记录了1024个undo log segment,而在每个undo log segment段中进行undo页的申请。
InnoDB 1.1版本开始,支持最大128个rollback segment,支持同时在线事务的限制提高到了128*1024。
从InnoDB 1.2开始,可通过参数对rollback segment做进一步的设置。这些参数包括:
-
innodb_undo_directory:文件所在位置,可以存放在独立表空间中,默认为'.',表示当前InnoDB存储引擎目录
-
innodb_undo_logs:rollback segment文件的个数
-
innodb_undo_tablespaces:构成rollback segment文件的数量
mysql> SHOW VARIABLES LIKE 'innodb_undo%' ;
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| innodb_undo_directory | . |
| innodb_undo_logs | 128 |
| innodb_undo_tablespaces | 0 |
+-------------------------+-------+
3 rows in set (0.01 sec)
事务提交后并不能马上删除undo log及undo log所在的页。这是因为可能还有其他事务需要通过undo log来得到行记录之前的版本。故事务提交时将undo log放入一个链表中,是否可以最终删除undo log及undo log所在页由purge线程来判断。
格式
-
insert undo log
指在insert操作中产生的undo log。因为insert操作的记录,只对事务本身可见,对其他事务不可见,故该undo log可以在事务提交后直接删除,不需要进行purge操作。
-
update undo log
对delete和update操作产生的undo log,该undo log可能需要提供MVCC机制,因此不能在事务提交时就进行删除。
格式图
purge
用于最终完成delete和update操作。
group commit
磁盘fsync的性能是有限的,为了提高磁盘效率,当前数据库都提供了group commit的功能,即一次fsync可以刷新确保多个事务日志被写入文件。对于InnoDB存储引擎来说,事务提交时会进行两个阶段的操作:
-
修改内存中事务对应的信息,并且将日志写入重做日志缓冲
-
调用fsync确保日志都从重做日志缓冲写入磁盘
在InnoDB 1.2版本之前,在开启二进制日志后,group commit功能会失效,从而导致性能的下降。MySQL 5.6采用Binary Log Group Commit(BLGC)解决。
7.3 事务控制语句
-
start transaction|begin
-
commit
-
rollback
-
savepoint identifier
-
release savepoint identifier
-
rollback to [savepoint] identifier
-
set transaction
7.4 隐式提交的SQL语句
-
DDL语句:alter、create、drop、rename table、truncate table(不能被回滚)
-
用来隐式地修改MySQL架构的操作:create user、drop user、grant、rename user、revoke、set password
-
管理语句:analyze table、cache index、check table、load index into cache、optimize table、repair table
7.5 不好的事务习惯
默认配置下,MySQL数据库总是自动提交的
-
在循环中提交
-
使用自动提交
-
使用自动回滚
-
长事务,执行时间长的事务,可以转换为小批量的事务来进行处理