PostgreSQL中的事务隔离-
PostgreSQL中的事务隔离
1 . 事务 隔离的概念
在数据库 管理系统中,事务隔离是一项重要的功能,它能确保在 并发访问 数据库时 事务 之间能够独立运行,不会相互干扰。数据库 系统 通常支持不同级别的事务隔离,用来满足不同应用程序之间的需求 。
2 . 事务 隔离的种类
常见的 事务隔离的 种类也 一共有 四种 , 包括 读未提交、 读 已提交、 可重复读和 可序列化 。 而 对于并发 的事务, 常见 的一些可能发生的行为包括 :
- 脏读 :一个事务读取了另一个未提交的事务写入的数据
- 不可重复读 :一个事务重新读取了前面 读取 过的数据,但是该数据已经发生了改变
- 幻读 :一个事务开始之后,需要根据 数据库 中现有的数据做一些更新,于是重新执行一个查询,返回符合查询条件的行,这个时候发现因为其他最近提交的事务自身发生改变,导致现有事务 如果继续执行可能 会发生错误。
下表代表的是不同 的事务隔离级别对应的可能会发生 的 行为的对照关系。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交 | 可能 | 可能 | 可能 |
读已提交 | 不可能 | 可能 | 可能 |
重复读 | 不可能 | 不可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 |
注 : 在 PG中 , 默认 的事务隔离级别是读已提交,而读未提交相当于是读已提交的一个更弱的版本。
这是 因为读已提交的隔离级别要求一个事务只能看到已经提交的数据修改,这意味着一个 事务不能读取 另一个事务尚未提交的数据变换 。那么这种 隔离级别提供了一定的数据一致性,防止脏读。这也是 为什么PG中 采用这种隔离级别为默认的隔离级别,因为他的适应性比较广。
而相比于 读已提交,读未提交的 隔离级别 不要求事务等待其他事务的提交,它允许一个事务读取另一个事务尚未提交的数据变化,这种 隔离 级别容易导致脏读,因为一个事务可能会读取到另一个正在被修改的事务,而这些 事务 可能会回滚,从而导致数据状态前后不一致 。
并且PG中 内部没有实现读未提交的隔离级别, 因为读未提交 的隔离级别存在严重的数据一致性问题,不符合事务的 ACID特性 ,所以并未实现读未提交,主要还是为了确保数据库的一致性和可靠性。
2. 1 读已提交
- P G 的 默认事务隔离级别
- 事务只能 看到已经提交的数据
- 可能会发生不可重复读 和幻读
案例 :
首先 创建一个 示例 表,其中包含如下的信息:
create table products(id serial primary key,name varchar(50),price numeric(10,2));
select * from products;
会话1:(读 操作 )
begin;
select * from products where id=1;
会话2:(写操作)
begin;
update products set price =66 where id = 1;
此时回到会话1:查询id=1,发现数据还是原来的数据,
会话2:
commit;
当会话2提交以后,回到会话1,就会发现数据进行了更改
这个案例说明了在读已提交隔离级别中,一个事务只能看到其他事务已经提交的数据修改,如果事务未提交,那么对于查询事务来说,这些修改是不可见的,直到其他事务提交为止
2.2 可重复读
- 保证在同一事务内的查询不会受到其他事务的影响
- 防止不可重复读,但是仍然可能发生幻读
- 适用场景:需要一定程度的数据一致性,可以容忍轻微的幻读。
案例
沿用上面的products表的数据,将修改的数据修改回原样。
会话1:
begin isolation level repeatable read ;
select * from products where id =1;
会话2:
此时会话2.执行更新语句,但不提交,在会话1中查看数据。
会话2:
对事务进行提交,再在事务1中查询对应的数据
可以发现,在会话1中,无论会话2提不提交,查询的结果都保持不变,即使会话2提交更新操作,查询结果仍然不变。
此时 ,除非对 会话1也进行提交 ,才可以看到改动 , 就相当于在事务的一开始对数据进行了快照,无论 如何改动 ,都不影响读取的结果。
2.3 串行化
- 最高级别的隔离,确保事务之间没有任何的交错或者是并发问题
- 通过锁定数据来实现,防止任何形式的并发问题,包括脏读、不可重复读、幻读
- 性能最差,因为他几乎完全禁止并发
- 适用场景:对数据一致性要求非常高,可以容忍较低的性能.
- 事务2会进行回滚,提交失败以后,事务的回滚其实就相当于没有执行
案例:
会话1:
开始串行化隔离,插入一条新的数据,查询现在的价格
会话2;
执行与会话1同样的操作, 其中开启事务
的语句是同时执行的 ,然后再分别插入数据。
可以看到, 两个会话中 新 插入的语句只有在 自己的 事务 中才可以查看到
此时 将会话 1事务进行 提交, 然后 将会话 2事务进行 提交, 可以看到 ,会话 1提交 成功,而会话 2会 提 交 失败 ,且会话2中 的事务发生了回滚,舍弃了之前的插入操作,
重新查询 两个会话中表的信息 , 发现 都 只能查询到会话 1提交的 事务。