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 | mysql> SELECT @@transaction_isolation; |
在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。我们的数据库锁,也是为了构建这些隔离级别存在的。总共有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次,得到的数据不一致,说明发生了不可重复读。
在可重复读隔离级别下,不会产生不可重复读:因为对每一行数据的读取会加上行级锁,这确保了在该事务进行期间,这些行不会被其他事务修改。
参考:脏读、幻读与不可重复读