引言
在MySQL数据库中,事务是一组不可分割的操作单元,这些操作要么全部成功,要么全部失败。事务的四大特性,通常被称为ACID特性,包括原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。以下是对这些特性以及并发事务问题的详细介绍:
一、事务的四大特性(ACID)
-
原子性(Atomicity)
- 事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
- 实现原子性的关键在于回滚日志(undo log),它记录了事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
-
一致性(Consistency)
- 事务必须使数据库从一个一致性状态变换到另一个一致性状态。
- 一致性是事务追求的最终目标,它的实现既需要数据库层面的保障,也需要应用层面的保障。
-
隔离性(Isolation)
- 当多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
- MySQL通过锁机制(如行级锁)和多版本并发控制(MVCC)来实现隔离性。
-
持久性(Durability)
- 一旦事务提交,则其所做的修改就会永久保存到数据库中,即使系统崩溃,修改的数据也不会丢失。
- 持久性是通过重做日志(redo log)来实现的,它保证了数据在事务提交后不会因宕机等原因而丢失。
二、并发事务问题
-
脏读(Dirty Read)
- 一个事务读取了另一个未提交事务的数据。
- 例如,事务T1修改了一个数据,事务T2随后读取了这个数据。如果T1撤销了这次修改,那么T2读取的数据就是脏数据。
- 脏读问题在读未提交(Read Uncommitted)隔离级别下可能发生。
-
不可重复读(Non-repeatable Read)
- 在一个事务范围内,多次查询却返回了不同的数据值。
- 这通常是因为在查询间隔内,被另一个事务修改并提交了数据。
- 不可重复读问题在读已提交(Read Committed)和读未提交(Read Uncommitted)隔离级别下可能发生。下面事务隔离演示会介绍
-
幻读(Phantom Read)
- 一个事务读取到的记录在其后续的读取请求中发生变化,造成原本能够查询到的数据在后续查询中消失或改变的现象。
- 例如,在一个事务中执行查询后,另一个事务插入了新记录,从而导致第一个事务再次执行同样的查询时会看到一个“幻影”记录。
- 幻读问题在可重复读(Repeatable Read)隔离级别下可能发生,但在串行化(Serializable)隔离级别下可以避免。
三、事务的隔离级别
MySQL数据库提供了四种事务隔离级别,从低到高分别为:
-
读未提交(Read Uncommitted)
- 一个事务可以读取另一个未提交事务的数据。
- 最低级别,任何情况都无法保证数据的一致性。
-
读已提交(Read Committed)
- 一个事务只能读取已经提交的事务所做的修改。
- 可避免脏读的发生。
-
可重复读(Repeatable Read)
- 保证在同一个事务中多次读取同样数据的结果是一样的。
- 可避免脏读和不可重复读的发生。
- MySQL的默认隔离级别。
-
串行化(Serializable)
- 事务串行化顺序执行,可避免脏读、不可重复读与幻读的发生。
- 级别最高,执行效率最低。
这些隔离级别可以解决哪些事务问题:
查看事务隔离级别:
# 查看隔离级别
select @@transaction_isolation;
设置事务隔离级别:
# 设置隔离级别为读未提交
set global transaction isolation LEVEL read uncommitted ;
# 设置隔离级别为读已提交
set session transaction isolation level read committed ;
# 设置隔离级别为可重复读
set global transaction isolation level repeatable read ;
# 设置隔离级别为串行化
set session transaction isolation level SERIALIZABLE ;