数据库事务隔离级别
数据库事务隔离级别
文章目录
- 数据库事务隔离级别
- 1. 并发事务问题
- 2. 事务隔离等级
- 3. 讨论:Repeatable Read 解决了幻读问题吗?
- 4. 构建幻读的例子
1. 并发事务问题
- 脏读:一个事务在处理过程中读取了另外一个事务未提交的数据。若另外一个事务回滚,则读取到的数据是无效的。
- 不可重复读:在一个事务内多次读取同一数据,在这个事务还没结束时,另外一个事务也访问了这个数据并对这个数据进行了修改,那么就可能造成第一个事务两次读取的数据不一致。
- 幻读:同一个事务内多次查询返回的结果集总数不一样(比如增加了或者减少了行记录)。
2. 事务隔离等级
隔离等级 | 描述 |
---|---|
READ UNCOMMITTED | 允许事务读取未被其他事务提交的变更,脏读,不可重复度和幻读的问题都会出现 |
READ COMMITTED | 允许事务读取已经被其它事务提交的变更,可以避免脏读,但不可重复读和幻读问题仍然可能出现 |
REPEATABLE READ | 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 |
SERIALIZABLE | 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。 |
3. 讨论:Repeatable Read 解决了幻读问题吗?
普通的幻读指的是当用户读取某一范围的数据行时,另一个事务又在该范围插入新行,当用户在读取该范围数据时会发现有新的“幻影行”
读操作分为快照读(Snapshot Read) 与当前读(Current Read)。
普通的查询是快照读,不会看到别的事务插入的数据。
-
快照读
快照读的数据是基于历史版本读取的快照信息(undolog历史版本),通过mvcc来进行并发控制,不用加锁。
-
当前读:读取的是最新的数据。
UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE
是当前读。当执行 select … for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题
4. 构建幻读的例子
- 首先我们创建一个
order
表,字段id
和amount
分别代码订单 id 和订单金额。
CREATE TABLE orders (
id INT PRIMARY KEY,
amount INT
);
INSERT INTO orders (id, amount) VALUES (1, 100);
INSERT INTO orders (id, amount) VALUES (2, 200);
INSERT INTO orders (id, amount) VALUES (3, 300);
- 分别在两个终端中执行以下两个事务
事务 1
START TRANSACTION
SELECT * FROM orders;
UPDATE orders SET amount = 300 WHERE id < 8;
SELECT * FROM orders;
UPDATE
事务 2
START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
INSERT INTO orders (id, amount) VALUES (7, 250);
COMMIT;
- 首先在终端1开启事务,并且执行查询语句
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
- 接下来在终端2执行 insert 指令添加命令,然后在终端一执行查询语句,观察到数据没有变化
- 接下来在终端1执行更新操作(更新操作需要涉及终端2 添加的数据),之后再次执行查询语句,发现出现幻读现象。
操作(更新操作需要涉及终端2 添加的数据),之后再次执行查询语句,发现出现幻读现象。