tonglin0325的个人主页

MySQL学习笔记——事务和隔离级别

ACID#

ACID数据库事务管理的四个关键属性,用于确保数据在并发环境下的可靠性和一致性。

1.Atomicity(原子性)#

原子性指的是一个事务中的所有操作要么全部执行成功,要么全部不执行。换句话说,事务是不可分割的最小单位。ACID模型的原子性主要涉及InnoDB事务。

例如,在银行转账操作中,假设从账户 A 转账到账户 B 是一个事务。如果在从 A 扣款后,B 未能成功入账,整个操作就会回滚到初始状态,A 账户的余额也不会减少。

相关的MySQL功能包括:

  • AUTOCOMMIT设置。
  • COMMIT语句。
     
  • ROLLBACK语句。

2.Consistency(一致性)#

数据库通常有各种完整性约束,如主键约束(Primary Key Constraint)、外键约束(Foreign Key Constraint)、唯一性约束(Unique Constraint)、检查约束(Check Constraint)等。一致性要求在事务执行之前和之后,这些约束必须始终满足。

例如,假设数据库要求每个用户的余额不能为负数,如果一个事务试图将用户的余额更新为负数,该事务将会失败并回滚,因为它违反了数据库的一致性约束。

3.Isolation(隔离性)#

隔离性指的是在并发环境下,各个事务相互隔离执行,事务的中间状态对其他事务是不可见的。这意味着每个事务的执行应该不会受到其他事务的影响。

数据库通过使用锁和其他并发控制机制来实现隔离性。例如,在两个事务同时试图更新同一条记录的情况下,数据库会确保这些事务不会相互干扰,一个事务必须在另一个事务完成之前等待。

4.Durability(持久性)#

持久性指的是一旦事务提交,数据库系统必须确保事务的结果被永久保存下来,即使在系统崩溃或断电的情况下也是如此。

这通常通过将事务的更改写入持久存储(如硬盘)来实现。例如,如果一个银行转账事务已经提交,即使服务器随后崩溃了,系统在恢复后仍然能保证该事务的结果是持久的,转账操作已被正确记录。

参考:https://dev.mysql.com/doc/refman/5.7/en/mysql-acid.html

InnoDB引擎如何保证ACID#

  • 原子性是通过 undo log(回滚日志) 来保证的;
  • 持久性是通过 redo log (重做日志)来保证的;
  • 隔离性是通过 MVCC(多版本并发控制) 或锁机制来保证的;
  • 一致性则是通过持久性+原子性+隔离性来保证;

MySQL数据库隔离级别#

可以使用如下命令查看MySQL的隔离级别,可重复读(Repeated Read)是****InnoDB的默认隔离级别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
mysql> SELECT @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'tx_isolation'; # 从 MySQL 5.7.20 和 8.0.3 开始,tx_isolation 已被弃用,推荐使用 transaction_isolation
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)

在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。我们的数据库锁,也是为了构建这些隔离级别存在的。总共有4种:

**1.未提交读(Read Uncommitted)**:允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

**2.提交读(Read Committed)**:只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)

3.可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,是****InnoDB的默认隔离级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读

4.串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

参考美团点评的文章:Innodb中的事务隔离级别和锁的关系

脏读、幻读与不可重复读#

脏读(dirty read:所谓脏读是指一个事务中访问到了另外一个事务未提交的数据

幻读(phantom read:在同一个事务中两次执行相同的查询,得到的记录数却因为其他事务的插入操作而不同。

具体来说,当一个事务 T1 多次查询满足某个条件的数据集时,另一个事务 T2 在两次查询之间插入了新的数据行,导致第二次查询返回了更多的行,这些新行就是“幻影”数据。

不可重复读(non-repeatable read:一个事务内,读取同一条记录2次,得到的数据不一致,说明发生了不可重复读。

在可重复读隔离级别下,不会产生不可重复读:因为对每一行数据的读取会加上行级锁,这确保了在该事务进行期间,这些行不会被其他事务修改。

参考:脏读、幻读与不可重复读