MySQL:Transaction:修订间差异

来自WHY42
(Riguz moved page MySQL:隔离级别 to MySQL:Transaction without leaving a redirect)
无编辑摘要
第1行: 第1行:
=ACID=
ACID,指数据库事务正确执行的四个基本要素的缩写。包含:
* 原子性(Atomicity)
* 一致性(Consistency)
* 隔离性(Isolation)
* 持久性(Durability)
一个支持事务(Transaction)的数据库,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。
==原子性==
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
==一致性==
*强一致性:读操作可以立即读到提交的更新操作。
*弱一致性:提交的更新操作,不一定立即会被读操作读到,此种情况会存在一个不一致窗口,指的是读操作可以读到最新值的一段时间。
*最终一致性:是弱一致性的特例。事务更新一份数据,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会读到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。
其他一致性变体还有:
*单调一致性:如果一个进程已经读到一个值,那么后续不会读到更早的值。
*会话一致性:保证客户端和服务器交互的会话过程中,读操作可以读到更新操作后的最新值。
==隔离性==
===脏读Dirty reads===
<q>
A dirty read (aka uncommitted dependency) occurs when a transaction is allowed to read data from a row that has been modified by another running transaction and not yet committed.
</q>
事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
{| class="two-columns"
|-
! Transaction 1 !! Transaction 2
|-
| <syntaxhighlight lang="sql">
/* Query 1 */
SELECT age FROM users WHERE id = 1;
/* will read 20 */
</syntaxhighlight> || -
|-
| - || <syntaxhighlight lang="sql">
/* Query 2 */
UPDATE users SET age = 21 WHERE id = 1;
/* No commit here */
</syntaxhighlight>
|-
| <syntaxhighlight lang="sql">
/* Query 1 */
SELECT age FROM users WHERE id = 1;
/* will read 21 */
</syntaxhighlight> || -
|-
| - || <syntaxhighlight lang="sql">
ROLLBACK; /* lock-based DIRTY READ */
</syntaxhighlight>
|}
===不可重复读 Non-repeatable reads===
在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。
{| class="two-columns"
|-
! Transaction 1 !! Transaction 2
|-
| <syntaxhighlight lang="sql">
/* Query 1 */
SELECT * FROM users WHERE id = 1;
</syntaxhighlight> || -
|-
| - || <syntaxhighlight lang="sql">
/* Query 2 */
UPDATE users SET age = 21 WHERE id = 1;
COMMIT; /* in multiversion concurrency
  control, or lock-based READ COMMITTED */
</syntaxhighlight>
|-
| <syntaxhighlight lang="sql">
/* Query 1 */
SELECT * FROM users WHERE id = 1;
COMMIT; /* lock-based REPEATABLE READ */
</syntaxhighlight> || -
|}
===幻读Phantom reads===
在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。
{| class="two-columns"
|-
! Transaction 1 !! Transaction 2
|-
| <syntaxhighlight lang="sql">
/* Query 1 */
SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
</syntaxhighlight> || -
|-
| - || <syntaxhighlight lang="sql">
/* Query 2 */
INSERT INTO users(id, name, age) VALUES (3, 'Bob', 27);
COMMIT;
</syntaxhighlight>
|-
| <syntaxhighlight lang="sql">
/* Query 1 */
SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
COMMIT;
</syntaxhighlight> || -
|}
===隔离级别(SQL:1992)===
事务的隔离级别从低到高有:
;Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
;Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
;Repeatable reads:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
;Serializable:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。
==持久性==
事务提交后,对系统的影响是永久的。
=MySQL=
MySQL支持SQL92标准中定义的各种事务隔离级别,参见[[事务:ACID]]。InnoDB引擎默认支持的级别是<span class="article-label">REPEATABLE READ</span>
MySQL支持SQL92标准中定义的各种事务隔离级别,参见[[事务:ACID]]。InnoDB引擎默认支持的级别是<span class="article-label">REPEATABLE READ</span>


第4行: 第125行:


[[Category:Database]]
[[Category:Database]]
[[Category:MySQL]]

2023年10月10日 (二) 03:00的版本

ACID

ACID,指数据库事务正确执行的四个基本要素的缩写。包含:

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

一个支持事务(Transaction)的数据库,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。

原子性

整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性

  • 强一致性:读操作可以立即读到提交的更新操作。
  • 弱一致性:提交的更新操作,不一定立即会被读操作读到,此种情况会存在一个不一致窗口,指的是读操作可以读到最新值的一段时间。
  • 最终一致性:是弱一致性的特例。事务更新一份数据,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会读到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。

其他一致性变体还有:

  • 单调一致性:如果一个进程已经读到一个值,那么后续不会读到更早的值。
  • 会话一致性:保证客户端和服务器交互的会话过程中,读操作可以读到更新操作后的最新值。

隔离性

脏读Dirty reads

A dirty read (aka uncommitted dependency) occurs when a transaction is allowed to read data from a row that has been modified by another running transaction and not yet committed.

事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。

Transaction 1 Transaction 2
/* Query 1 */
SELECT age FROM users WHERE id = 1;
/* will read 20 */
-
-
/* Query 2 */
UPDATE users SET age = 21 WHERE id = 1;
/* No commit here */
/* Query 1 */
SELECT age FROM users WHERE id = 1;
/* will read 21 */
-
-
ROLLBACK; /* lock-based DIRTY READ */

不可重复读 Non-repeatable reads

在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。

Transaction 1 Transaction 2
/* Query 1 */
SELECT * FROM users WHERE id = 1;
-
-
/* Query 2 */
UPDATE users SET age = 21 WHERE id = 1;
COMMIT; /* in multiversion concurrency
   control, or lock-based READ COMMITTED */
/* Query 1 */
SELECT * FROM users WHERE id = 1;
COMMIT; /* lock-based REPEATABLE READ */
-

幻读Phantom reads

在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。

Transaction 1 Transaction 2
/* Query 1 */
SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
-
-
/* Query 2 */
INSERT INTO users(id, name, age) VALUES (3, 'Bob', 27);
COMMIT;
/* Query 1 */
SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
COMMIT;
-

隔离级别(SQL:1992)

事务的隔离级别从低到高有:

Read Uncommitted
最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
Read Committed
只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
Repeatable reads
在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
Serializable
事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

持久性

事务提交后,对系统的影响是永久的。

MySQL

MySQL支持SQL92标准中定义的各种事务隔离级别,参见事务:ACID。InnoDB引擎默认支持的级别是

  • 在REPEATABLE READ级别下,InnoDB通过防止幻读。