事务概念
事务:
- 构成单一逻辑单元的操作集合.
- 是访问并可能更新各种数据项的一个程序执行单元(unit).
- 事务是不可分割的, 要么执行全部内容, 要么一个也不执行.
ACID特性:
- 原子性(atomicity): 事务的所有操作在数据库中要么全部正确反映出来, 要么完全不反映.保证原子性的基本思路: 对于事务要执行写操作的数据项, 数据库系统在磁盘上记录其旧值. 这个信息记录在称为日志的文件中. 如果事务没能完成它的执行, 数据库系统从日志中恢复旧值, 使得看上去事务从未执行过. 保证原子性是数据库系统的责任, 这项工作由称为恢复系统(recovery system)的一个数据库组件处理.
- 一致性(consistency): 隔离执行事务时(即:在没有其他事务并发执行的情况下)保持数据库的一致性.数据库总是从一个一致性状态转换到另外一个一致性状态.
- 隔离性(isolation): 尽管多个事务可能并发执行, 但系统保证, 对于任何一对事务A和B, 在A看来, B或者在A开始之前已经完成执行, 或者在A完整之后开始执行. 因此, 每个事务都感觉不到系统中有其他事务在并发地执行.事务的隔离性确保事务并发执行后的系统状态与这些事务以某种次序一个接一个的执行后的状态是等价的.确保隔离性是数据库系统中称为并发控制系统(concurrency-control system)的部件的责任.
- 持久性(durability): 一个事务成功完成后, 它对数据库的改变必须是永久的, 即使出现系统故障.可以通过确保以下两条中的任何一条来达到持久性(同样由恢复系统保证持久性):事务做的更新在事务结束前已经写入磁盘.有关事务已执行的更新信息已写到磁盘上, 并且此类信息必须充分, 能让数据库系统出现故障后重新启动时重新构造更新.
1.2.2事务原子性和持久性
事务状态:
- 活动的(active): 初始状态, 事务执行时处于这个状态.
- 部分提交的(partially committed): 最后一条语句执行后.
- 失败的(failed): 发现正常的执行不能继续后.
- 中止的(aborted): 事务回滚并且数据库已恢复到事务开始前的状态后.
- 提交的(committed): 事务成功完成后.
1.2.3事务隔离性
可串行化(serializable): 在并发执行中, 通过保证所执行的任何调度的效果都与没有并发执行的调度效果一样, 则可以确保数据库的一致性. 也就是说: 调度应该在某种意义上等价于一个串行调度.
1.2.4可串行化
冲突(conflict): 当I和J是不同事物在相同数据项Q上的操作, 并且其中至少有一个是write(Q)指令时, 则I和J是冲突的.
冲突等价(conflict equivalent): 如果调度A可以经过一系列非冲突指令交换转换成B, 称A和B是冲突等价的.
冲突可串行化(conflict serializable): 若一个调度S与一个串行调度冲突等价, 则称调度S是冲突可串行化的.
1.2.5可恢复性
- 可恢复调度(recoverable schedule): 应满足: 对于每对事务A和B, 如果B读取了之前由A所写的数据项, 则A先于B提交.
- 无级联调度(cascadeless schedule)级联回滚(cascading rollback): 因单个事务故障导致一系列事务回滚的现象.无级联调度: 对于每对事务A和B, 如果B读取了先前由A所写的数据项, 则A必须在B这一读操作前进行提交.每一个无级联调度也都是一个可恢复调度.
- 事务隔离级别可串行化(serializable): 通常保证可串行化调度. 是最高的隔离级别, 通过强制事务串行执行, 避免了幻读的问题. 简单来说: 可串行化会在读取的每一行数据上都加锁, 所以可能导致大量的超时和锁争用的问题. 实际应用中, 很少考虑这个级别, 只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别.可重复读(repeatable read):只允许读取已提交数据, 而且在一个事务两次读取一个数据项期间, 其他事务不得更新该数据.解决了脏读的问题. 该级别保证了在同一个事务中多次读取同样记录的结果是一致的.但无法解决幻读(phantom read)的问题. 幻读: 指的是当某个事务在读取某个范围内的记录时, 另外一个事务又在该范围内插入了新的记录, 当之前的事务再次读取该范围的记录时, 会产生幻行(phantom row). InnoDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题. 可重复读是MySQL的默认事务隔离级别.已提交读(read committed): 只允许读取已提交数据, 但不要求可重复读. 一个事务开始时,只能"看见"已经提交的事务所做的修改. 换句话说: 一个事务从开始直到提交之前, 所做的任何修改对其他事务都是不可见的. 也叫做不可重复读(nonrepeatable read), 因为两次执行同样的查询,可能会得到不一样的结果.未提交读(read uncommitted): 允许读取未提交读. 事务可以读取未提交的数据, 这种也被称为脏读(dirty read). 实际应用中一般很少使用.以上所有隔离级别都不允许脏写(dirty write), 即如果一个数据项已经被另外一个尚未提交或中止的事务写入, 则不允许对该数据项执行写操作.
1.2.6死锁
死锁(dead lock): 指两个或多个事务在同一资源上相互占用, 并请求锁定对方占用的资源, 从而导致恶性资源竞争的现象.
- 当多个事务试图以不同的顺序锁定资源时, 就可能会产生死锁.
- 多个事务同时锁定一个资源时, 也会产生死锁.
1.2.7事务日志
事务日志: 使用事务日志, 存储引擎在修改表的数据时, 只需要修改其内存拷贝, 再把该修改行为记录到持久在硬盘上的事务日志中, 而不用每次都将修改的数据本身持久到磁盘.
特点: 事务日志采用追加的方式, 因此写日志的操作时磁盘上一小块区域内的顺序IO, 而不像随机IO需要在磁盘的多个地方移动磁头, 所以采用事务日志的方式相对来说会很快.
预写式日志(write-ahead logging): 事务日志持久以后, 内存中被修改的数据在后台可以慢慢地刷回到磁盘. 所以修改数据需要写两次磁盘.
系统崩溃情况: 如果数据的修改已经记录到事务日志并持久化, 但数据本身还没有写入到磁盘, 此时系统崩溃, 存储引擎在重启时能够自动恢复这部分修改的数据.