以下英文截图均来自 mysql5.7官方文档
一. 数据库事务
事务(transaction): 事务是可以提交或 回滚的原子工作单元 。当事务对数据库进行多次更改时,要么在提交事务后所有更改成功,要么在回滚事务时撤消所有更改。 大白话是对数据库的一组操作,要么全部成功,要么全部失败(事务回滚)。
二. 特性
- ACID
代表原子性,一致性,隔离性和持久性的首字母缩写。这些属性都是数据库系统所需要的,并且都与事务的概念紧密相关 。InnoDB
遵守ACID
原则的事务功能。
2.1 原子性
事务是可以提交或回滚的原子工作单元。当事务对数据库进行多次更改时,要么在提交事务后所有更改成功,要么在回滚事务时撤消所有更改。
2.2 一致性
在每次提交或回滚之后以及正在进行事务期间,数据库始终保持一致状态。如果正在多个表之间更新相关数据,则查询将看到所有旧值或所有新值,而不是新旧值的混合。
2.3 隔离性
事务在进行过程中相互保护(隔离);他们不能互相干扰,也不能看到彼此的未提交数据。这种隔离是通过锁定机制实现的。有经验的用户可以确定事务确实不会相互干扰时,可以调整隔离级别,减少保护措施,而提高性能和 并发性。
2.4 持久性
事务的结果是持久的:提交操作成功后,该事务所做的更改就不会出现电源故障,系统崩溃,竞争状况或许多非数据库应用程序容易受到的其他潜在危险。耐用性通常涉及写入磁盘存储,并具有一定数量的冗余以防止写入操作期间出现电源故障或软件崩溃。(在中 InnoDB
,双写缓冲区有助于持久性。)
三. 隔离级别
隔离级别
数据库处理的基础之一。隔离是缩写ACID
中的 I
; 隔离级别是一种设置,用于在多个事务同时进行更改和执行查询时微调性能与结果的可靠性,一致性和可重复性之间的平衡。
从最高程度的一致性和保护到最低程度,InnoDB
支持的隔离级别为: SERIALIZABLE
, REEATABLE READ
, READ COMMITTED
和 READ UNCOMMITTED
。
使用InnoDB
表,许多用户可以为所有操作保留默认的隔离级别(REPEATABLE READ
)。专家用户可能会选择 READ COMMITTED
级别,因为他们通过OLTP
处理或在数据仓库操作期间突破可伸缩性的界限 ,在这些操作中微小的不一致不会影响大量数据的汇总结果。边缘的级别(SERIALIZABLE
和 READ UNCOMMITTED
)将处理行为更改为很少使用的程度。
3.1 SERIALIZABLE
– 可序列化
可序列化
该隔离级别,使用最保守的锁定策略,以防止任何其他事务插入或改变的数据被当前事务读取,直到它完成。这样,可以在一个事务中一遍又一遍地运行相同的查询,并确保每次都检索相同的结果集。自当前事务开始以来,任何尝试更改另一事务提交的数据的尝试都会导致当前事务等待。
这是SQL
标准指定的默认隔离级别。实际上,很少需要这种严格程度,因此默认的隔离级别 InnoDB
是下一个最严格的 REPEATABLE READ
。
3.2 REPEATABLE READ
– 可重复读
可重复读
默认的隔离级别的 InnoDB
。它可以防止被查询的任何行被其他事务更改 ,从而阻止不可重复的读取,但不会 阻止 幻像读取。它使用中等严格的锁定 策略,以便事务中的所有查询都可以查看来自同一快照的数据,即事务开始时的数据。
当此隔离级别进行事务UPDATE ... WHERE
,DELETE ... WHERE
,SELECT ... FOR UPDATE
,和 LOCK IN SHARE MODE
操作,其他事务可能必须等待。
3.3 READ COMMITTED
– 读已提交
读已提交
为了提高性能,使用 锁定策略 的隔离级别放松了事务之间的某些保护 。事务无法看到来自其他事务的未提交的数据,但是它们可以看到在当前事务启动后另一个事务提交的数据。因此,一个事务永远不会看到任何不良数据,但是它确实看到的数据可能在某种程度上取决于其他事务的时间安排。
具有此隔离级别的事务执行 UPDATE ... WHERE
或DELETE ... WHERE
操作时,其他事务可能必须等待。该事务可以执行SELECT ... FOR UPDATE
和LOCK IN SHARE MODE
操作,而无需等待其他事务。
3.4 READ UNCOMMITTED
– 读未提交
读未提交
在事务之间提供最少保护的隔离级别。查询采用一种锁定策略,该策略允许它们在通常会等待其他事务的情况下继续执行。但是,这种额外的性能是以较不可靠的结果为代价的,这些结果包括已被其他事务更改但尚未提交的数据(称为脏读))。谨慎使用此隔离级别,请注意结果可能不一致或不可重复,这取决于其他事务在同时进行。通常,具有此隔离级别的事务仅执行查询,而不执行插入,更新或删除操作。
四. 并发情况下可能产生的问题
4.1 脏读
检索不可靠数据的操作,该数据是由另一个事务更新但尚未 提交的数据。只有隔离级别称为read uncommitted
才有可能。
这种操作不符合数据库设计的 ACID
原则。由于数据可能会回滚或在提交之前进一步更新,因此被认为具有很高的风险 。那么,进行脏读的事务将使用从未被确认为准确的数据。
与之相反的是“ 一致读取”,即InnoDB
确保即使一个事务同时提交,事务也不会读取由另一个事务更新的信息。
4.2 幻读
在查询的结果集中出现的行,但在较早的查询的结果集中没有出现的行。例如,如果一个查询在一个事务中运行了两次,同时,另一个事务将在插入新行或更新一行以使其与WHERE查询的子句匹配之后提交 。
这种情况称为幻读。与不可重复读取相比,要防备更加困难,因为锁定第一个查询结果集中的所有行并不能防止导致幻像出现的更改。
在不同的隔离级别中,可序列化的读取级别阻止了幻像读取,而可重复的读取, 一致的读取和 未提交的读取级别则允许幻像读取 。
4.3 不可重复读
查询检索数据,而同一事务中的后续查询 检索应为相同数据的情况,但查询返回不同的结果(与此同时,其他提交的事务已更改)。
这种操作违背了数据库设计的 ACID
原则。在交易中,数据应保持一致,并具有可预测和稳定的关系。
在不同的隔离级别中,可序列化的读取级别和 可重复的读取级别可防止不可重复的读取,而一致的读取和未提交的级别则允许不可重复的读取 。
五. 其他
5.1 一致阅读
一种读取操作,使用 快照信息可基于某个时间点显示查询结果,而不管同时运行的其他事务执行的更改如何。如果查询的数据已被另一个事务更改,则将基于撤消日志的内容来重建原始数据 。通过强制事务等待其他事务完成,该技术避免了一些可以减少并发性的锁定问题。
使用REPEATABLE READ
隔离级别时,快照基于执行第一次读取操作的时间。使用READ COMMITTED
隔离级别,快照将重置为每个一致的读取操作的时间。
一致读取是默认模式,在该模式下以 READ COMMITTED
和REPEATABLE READ
隔离级别InnoDB
处理SELECT
语句。因为一致读取不会在它访问的表上设置任何锁,所以在对表执行一致读取时,其他会话可以自由地修改这些表。