事务
一组逻辑操作单元, 使数据从一种状态变换为另一种状态;
ACID 特性
原子性(atomicity)
指事务是一个不可分割的工作单位, 要么全部提交, 要么全部失败回滚;
一致性(consistency)
指事务执行前后, 数据从一个合法性状态到另一个合法性状态; 即满足现实世界中的约束, 比如银行账户余额一定要大于等于0;
隔离性(isolation)
指一个事务的执行不能被其他事务干扰, 即一个事务内部的操作及使用的数据对并发的其他事务是隔离的, 并发执行的各个事务之间不能互相干扰;
持久性(durability)
指一个事务一旦被提交, 对数据中数据的改变就是永久性的, 接下来的其他操作和数据库故障不该对其有任何影响;
持久性是通过事务日志来保证的, 日志包括了重做日志和回滚日志; 当对数据进行修改时, 首先会将数据库的变化信息记录到重做日志中, 然后再对数据库中对应的行进行修改; 如此即使数据库系统崩溃, 数据库重启后也能找到没有更新到数据库系统中的重做日志, 重新执行, 从而使事务具有持久性;
总结
原子性是基础, 隔离性是手段, 一致性是约束条件, 持久性是目的;
事务状态
活动的(active)
事务对应的数据库操作正在执行过程中时, 事务处在 活动的 状态;
部分提交的(partially committed)
事务的最后一个操作执行完成, 由于操作都在内存中执行, 造成的影响并没有刷新到磁盘, 此时事务处在 部分提交的 状态;
失败的(failed)
当数据处在 活动的 或者 部分提交的 状态时, 可能遇到某些错误导致无法继续执行, 或者人为停止事务执行, 此时事务处在 失败的 状态;
中止的(aborted)
如果事务执行一部分而变为失败的状态, 则需要把已经修改的事务中的操作还原到事务执行前的状态; 即撤销失败事务对当前数据库造成的影响, 这个撤销过程称之为 回滚;
回滚操作执行完毕后, 即数据库恢复到执行事务前的状态, 即事务处在 中止的 状态;
提交的(committed)
当事务处在 部分提交的 状态的事务将修改过的数据都同步到磁盘上, 就说事务处在了 提交的 状态;
基本操作
基本步骤:
- 开启事务
- 一系列操作
- 事务结束(提交、中止)
并发事务问题
在 MySQL 同时处理多个事务的时候, 就可能会出现脏读、不可重复读、幻读的问题;
这三种问题的严重程度依次为:脏读 > 不可重复读 > 幻读;
脏读
脏读是指假设事务 B 读取到了事务 A 未提交的数据, 若此时事务 A 回滚, 则事务 B 读取到的数据为过期数据;
不可重复读
指在事务 A 内多次读取同一个数据, 此时同一个数据被另一个事务 B 修改并提交, 此时事务 A 再次读取同一个数据时, 发现前后两次读到的数据是不一致的;
幻读
指一个事务 A 多次查询某个符合查询条件的 记录数量, 结果事务 B 在此时增加或删除了一条符合查询条件的记录数量, 则事务 A 再次查询符合条件的记录数量时, 前后不一致, 则发生了幻读;
事务隔离级别
SQL标准一共有如下四种隔离级别来解决并发事务可能出现的三种问题(隔离级别从低到高, 性能从高到低):
- 读未提交(read uncommitted):指一个事务还没提交时, 对数据的修改能被其他事务看到; 此时可能会发生脏读、不可重复读、幻读现象;
- 读提交(read committed):指一个事务提交之后, 对数据的修改才能被其他事务看到; 此时可能会发生不可重复读、幻读现象;
- 可重复读(repeatable read):指一个事务执行过程中看到的数据, 与事务启动时看到的数据一致; 是MySQL InnoDB 引擎的默认隔离级别; 此时可能会发生幻读现象
- 串行化(serializable):对记录加读写锁, 当多个事务对记录进行读写操作时, 如果发生了读写冲突, 后访问的事务必须等前一个事务执行完成, 才能继续执行; 此时脏读、不可重复读、幻读均不可能会发生;