在PG内部,可以设置三个不同的隔离级别,对应于读提交、可重复读取和可序列化的级别。默认为READ COMMITTED。
ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
这个在另一篇文章中有介绍和实验。
READ COMMITTED隔离级别,意味着可以看到已提交的数据,无法看到未提交的数据,所以可能造成幻读。
当我们有需要的时候,可以选择更高的安全隔离级别,REPEATABLE READ,提供了更强的保证。意味着我们只能看到事务开始之前已经提交的数据。在事务完成之前,其他回话引起的任何更改对我们都是不可见。
重点是,每个事务都具有不同的数据库数据。每个事务都可以看到以前事务提交的数据的快照,以及在事务本身中创建的所有尚未提交的数据。
“以前的事务”的含义取决于您何时开始您的语句(在read committed中)或何时开始您的事务(在repeatable read中),但在这两种情况下,都无法选择。如果需要同步状态,这可能是一个问题,因为无法保证不同的语句或事务将完全同时启动。
这时,可以设置你想看哪个事务之前的数据,设置一个snapshot。
创建一个实验表。
create table test0115(id int);
session A: 查询一个snapshot点
mytest=# begin;
BEGIN
mytest=# select pg_export_snapshot();
pg_export_snapshot
---------------------
00000007-00000037-1
(1 row)
session B: 一个插入数据的事务
mytest=# begin;
BEGIN
mytest=# insert into test0115(id) values (1);
INSERT 0 1
mytest=# insert into test0115(id) values (2);
INSERT 0 1
mytest=# commit;
COMMIT
Session C: 关键点!!!
mytest=# select * from test0115;
id
----
1
2
(2 rows)
mytest=# begin isolation level repeatable read;
BEGIN
mytest=# set transaction snapshot '00000007-00000037-1';
SET
mytest=# select * from test0115 ;
id
----
(0 rows)
是不是灰常神奇的操作!
我们来看看数据库做了哪些操作。
当我们执行了Session A 中的语句之后,数据库在$PGDATA/pg_snapshots文件夹下生成了与snapshot同名的文件。
查看文件内容为
vxid:6/328
pid:32460
dbid:16385
iso:1
ro:0
xmin:10093
xmax:10093
xcnt:0
sof:0
sxcnt:0
rec:0
记录了snapshot的一些信息。当我们查询的时候,我们会根据这些版本号,去表中去查询。
mytest=# select xmin,cmin,xmax,cmax,ctid from test0115;
xmin | cmin | xmax | cmax | ctid
-------+------+------+------+-------
10094 | 0 | 0 | 0 | (0,1)
10095 | 0 | 0 | 0 | (0,2)
(2 rows)