事务的 ACID 特性
-
原子性(Atomicity)
-
一致性(Consistency)
-
隔离性(Isolation)
-
持久性(Durability)
事务的隔离级别
- 读未提交:一个事务还没提交时,它做的变更就能被别的事务看到。
- 读提交:一个事务提交之后,他做的变更才会被别的事务看到
- 可重复读(MySQL 默认隔离级别):一个事务在执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读级别下,未提交变更对其他事务也是不可见的。
- 串行化:顾名思义是对同一行记录,写会加写锁,读会加读锁。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
查看 MySQL 事务隔离级别
show variables like 'transaction_isolation'
MVCC 多版本并发控制
MVCC 只在 可重复读和读提交两个隔离级别下工作。
MVCC 的实现,是通过保存数据在某个时间点的快照来实现的,也就是说,不管需要自行多长时间,每个事务看到的数据都是一致的。
InnoDB 的 MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存了行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号。每开始一个新的事务,系统版本号都会自动递增,事务开始时刻的系统版本号回做为事务的版本号,用来和查询到的每行记录的版本号进行比较。
在可重复读隔离级别下,MVCC 具体操作流程:
-
SELECT:InnoDB 会根据以下两个条件检查每行记录:
- a. InnoDB 只查找版本号早于当前事务版本的数据行(也就是,行的系统版本号小于或等于系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么就是事务自身插入或者修改过的。
- b. 行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除
-
INSERT:InnoDB 为新插入的每一行保存当前系统版本号作为行版本号
-
DELETE:InnoDB 为删除的每一行保存当前系统版本号作为行删除标识
-
UPDATE:InnoDB 为插入一行记录(回滚段的一条回滚记录),保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识(重要)
同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)
回滚日志的删除时机
系统会判断,当没有事务再需要用到回滚日志时,回滚日志会被删除,也就是说,当系统里没有事务的系统版本号小于这个回滚日志的系统版本号时,系统会删除回滚日志。
事务的启动方式
-
显示启动事务语句,begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback
-
set autocommit = 0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。
建议总是使用 set autocommit = 1,通过显示语句的方式来启动事务,避免意外的长事务
show variables like 'autocommit'
可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务。
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60