@SovietPower
2022-06-05T22:26:31.000000Z
字数 22742
阅读 953
DB
1. 在Dokcer环境中启动之前实验创建的openGauss容器。
2. 连接到数据库db2022(将该会话记作 T1 )
PS H:\> docker exec -it opengauss3 bash
root@97375c3acbd1:/# su omm
omm@97375c3acbd1:/$ gsql -d db2022 -r
3. 在 T1 中执行以下SQL语句,创建用于事务 隔离级别(Isolation Level) 测试的数据表
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
4. 在 T1 中执行以下语句,查看并设置当前会话的参数
lockwait_timeout
:控制单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
update_lockwait_timeout
:允许并发更新参数开启情况下,该参数控制并发更新同一行时单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
延长update_lockwait_timeout
,则多个事务并行执行时等待锁的时间更长,方便输入语句测试。
db2022=# select current_setting('transaction_isolation');
current_setting
-----------------
read committed
(1 row)
db2022=# show update_lockwait_timeout;
update_lockwait_timeout
-------------------------
2min
(1 row)
db2022=# set update_lockwait_timeout to 1200000;
SET
db2022=# show update_lockwait_timeout;
update_lockwait_timeout
-------------------------
20min
(1 row)
db2022=# \timing
Timing is on.
5. 打开另一个PowerShell窗口,连接到数据库db2022(将该会话记作 T2 ),执行
db2022=# set update_lockwait_timeout to 1200000;
SET
db2022=# \timing
Timing is on.
read committed 隔离级别可以避免 Write Cycles 异常
Read Commited保证:
读数据时只能读到已经提交了的数据 (没有脏读)
写数据时只能覆盖已经提交了的数据 (没有脏写)
6.7. 在 T1,T2 中都执行以下语句,设置当前会话的事务隔离级别
db2022=# begin;
BEGIN
Time: 0.315 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.446 ms
8. 在 T1 中执行以下语句,对test表中id=1的记录进行更新
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.730 ms
9. 在 T2 中执行以下语句,同样对test表中id=1的记录进行更新
db2022=# update test set value = 12 where id = 1;
此时,T2中的事务被阻塞
UPDATE 1
Time: 44844.698 ms
10. 在 T1 中执行以下语句,对test表中id=2的记录进行更新,然后提交事务
db2022=# update test set value = 21 where id = 2;
UPDATE 1
Time: 0.663 ms
db2022=# commit;
COMMIT
Time: 411.061 ms
此时结束对T2中事务的阻塞
1. 在 T1 中执行以下语句,查询test表中的数据
此时 T2 修改未提交
db2022=# select * from test;
id | value
----+-------
1 | 11
2 | 21
(2 rows)
Time: 0.615 ms
2. 在 T2 中执行以下语句,对test表中id=2的记录进行更新,然后提交事务
db2022=# update test set value = 22 where id = 2;
UPDATE 1
Time: 0.521 ms
db2022=# commit;
COMMIT
Time: 294.785 ms
3. 在 T2 中执行以下语句,查询test表中的数据
db2022=# select * from test;
id | value
----+-------
1 | 12
2 | 22
(2 rows)
Time: 0.903 ms
read committed 隔离级别可以避免 Aborted Reads 异常
4. 在 T1 中执行以下语句,重置测试数据表
db2022=# drop table test;
DROP TABLE
Time: 1656.834 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 9758.841 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 3422.961 ms
5. 在 T1 中执行以下语句,设置当前会话的事务隔离级别
db2022=# begin;
BEGIN
Time: 0.375 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.368 ms
6. 在 T2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# begin;
BEGIN
Time: 0.575 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.459 ms
7. 在 T1 中执行以下语句,对test表中id=1的记录进行更新
db2022=# update test set value = 101 where id = 1;
UPDATE 1
Time: 0.956 ms
8. 在 T2 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 1.169 ms
9. 在 T1 中执行以下语句,撤销事务
db2022=# abort;
ROLLBACK
Time: 0.666 ms
10. 在 T2 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 0.776 ms
db2022=# commit;
COMMIT
Time: 0.526 ms
read committed 隔离级别可以避免 intermediate Reads 异常
1. 在 T1 中执行以下语句,重置测试数据表
db2022=# drop table test;
DROP TABLE
Time: 3017.035 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 11315.591 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 2152.651 ms
2. 在 T1 中执行以下语句,设置当前会话的事务隔离级别
db2022=# begin;
BEGIN
Time: 0.284 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.495 ms
3. 在 T2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# begin;
BEGIN
Time: 0.389 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.415 ms
4. 在 T1 中执行以下语句,对test表中id=1的记录进行更新
db2022=# update test set value = 101 where id = 1;
UPDATE 1
Time: 0.601 ms
5. 在 T2 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 0.716 ms
6. 在 T1 中执行以下语句,再次对test表中id=1的记录进行更新,然后提交
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.577 ms
db2022=# commit;
COMMIT
Time: 2151.811 ms
7. 在 T2 中执行以下语句,再次查询test表中数据
db2022=# select * from test;
id | value
----+-------
2 | 20
1 | 11
(2 rows)
Time: 0.513 ms
read committed 隔离级别可以避免 Circular Information Flow 异常
8. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
db2022=# begin;
BEGIN
db2022=# set transaction isolation level read committed;
SET
1. 在 T1 中执行以下语句,对test表中id=1的记录进行更新
db2022=# update test set value = 11 where id = 1;
UPDATE 1
2. 在 T2 中执行以下语句,对test表中id=2的记录进行更新
db2022=# update test set value = 22 where id = 2;
UPDATE 1
3. 在 T1 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
2 | 20
1 | 11
(2 rows)
4. 在 T2 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
1 | 10
2 | 22
(2 rows)
5. 在 T1 中执行以下语句,提交事务
db2022=# commit
db2022-# ;
COMMIT
6. 在 T2 中执行以下语句,提交事务
db2022=# commit;
COMMIT
db2022=# select * from test;
id | value
----+-------
1 | 11
2 | 22
(2 rows)
read committed 隔离级别可以避免 Observed Transaction Vanishes 异常
7. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
db2022=# begin;
BEGIN
db2022=# set transaction isolation level read committed;
SET
10. 打开一个新的PowerShell窗口,连接到数据库db2022(将该会话记作 T3 ),执行
db2022=# set update_lockwait_timeout to 1200000;
SET
db2022=# \timing
Timing is on.
db2022=# begin;
BEGIN
Time: 0.234 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.431 ms
1. 在 T1 中执行以下语句,对test表中记录进行更新
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.585 ms
db2022=# update test set value = 19 where id = 2;
UPDATE 1
Time: 0.509 ms
在 T2 中执行以下语句,对test表中记录进行更新
db2022=# update test set value = 12 where id = 1;
阻塞
2. 在 T1 中执行以下语句,提交事务
db2022=# commit;
COMMIT
Time: 106.829 ms
T2结束阻塞
3. 在 T3 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
1 | 11
2 | 19
(2 rows)
Time: 0.971 ms
4. 在 T2 中执行以下语句,对test表中记录进行更新
db2022=# update test set value = 18 where id = 2;
UPDATE 1
Time: 0.562 ms
5. 在 T3 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
1 | 11
2 | 19
(2 rows)
Time: 0.560 ms
6. 在 T2 中执行以下语句,提交事务
db2022=# commit;
COMMIT
Time: 118.936 ms
7. 在 T3 中执行以下语句,查询test表中数据
db2022=# select * from test;
id | value
----+-------
1 | 12
2 | 18
(2 rows)
Time: 0.778 ms
提交的事务不会丢失。
read committed 隔离级别不能避免 Predicate-Many-Preceders 异常
8. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 6818.855 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 211.857 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 135.669 ms
db2022=# begin;
BEGIN
Time: 0.283 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.323 ms
1. 在 T1 中执行以下语句,查询test表中数据
db2022=# select * from test where value = 30;
id | value
----+-------
(0 rows)
Time: 0.839 ms
2. 在 T2 中执行以下语句,向test表中插入数据,然后提交
db2022=# insert into test (id, value) values(3, 30);
INSERT 0 1
Time: 0.656 ms
db2022=# commit;
COMMIT
Time: 36.350 ms
3. 在 T1 中执行以下语句,查询test表中数据
db2022=# select * from test where value % 3 = 0;
id | value
----+-------
3 | 30
(1 row)
Time: 1.058 ms
db2022=# commit
db2022-# ;
COMMIT
Time: 0.319 ms
第二次查询的结果并不在第一次中,不可重复读。
read committed 隔离级别不能避免 Predicate-Many-Preceders for write
predicates 异常
4. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 136.073 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 229.252 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 67.571 ms
db2022=# begin;
BEGIN
Time: 0.325 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.371 ms
7. 在 T1 中执行以下语句,更新表test中的数据
db2022=# update test set value = value + 10;
UPDATE 2
Time: 1.114 ms
8. 在 T2 中执行以下语句,删除表test中value为20的记录
db2022=# delete from test where value = 20;
阻塞
9. 在 T1 中提交事务
10. 在 T2 中执行以下语句,查询表test中value为20的记录
db2022=# select * from test where value = 20;
id | value
----+-------
1 | 20
(1 row)
Time: 0.805 ms
T2 删除了所有 value=20 的记录,但删除后依旧能查到 value=20 的记录。
read committed 隔离级别不能避免 Lost Update 异常
1. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 155.979 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 690.676 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 66.225 ms
db2022=# begin;
BEGIN
Time: 0.259 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.453 ms
4. 在 T1 中执行以下语句,查询表test中id为1的记录
db2022=# select * from test where id = 1;
id | value
----+-------
1 | 10
(1 row)
Time: 0.572 ms
5. 在 T2 中执行以下语句,查询表test中id为1的记录
db2022=# select * from test where id = 1;
id | value
----+-------
1 | 10
(1 row)
Time: 0.942 ms
6. 在 T1 中执行以下语句,更新表test中id为1的记录
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.832 ms
7. 在 T2 中执行以下语句,更新表test中id为1的记录
db2022=# update test set value = 12 where id = 1;
阻塞
8. 在 T1 2 中提交事务
db2022=# select * from test;
id | value
----+-------
2 | 20
1 | 12
(2 rows)
Time: 0.777 ms
T1 的更新丢失。
read committed 隔离级别不能避免 Read Skew 异常
10. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 145.889 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 268.693 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 56.577 ms
db2022=# begin;
BEGIN
Time: 0.309 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.480 ms
3. 在 T1 中执行以下语句,查询表test中id为1的记录
db2022=# select * from test where id = 1;
id | value
----+-------
1 | 10
(1 row)
Time: 0.623 ms
4. 在 T2 中执行以下语句,查询并更新表test中的记录,然后提交事务
db2022=# select * from test where id = 1; --返回(1,10)
id | value
----+-------
1 | 10
(1 row)
Time: 0.761 ms
db2022=# select * from test where id = 2; --返回(2,20)
id | value
----+-------
2 | 20
(1 row)
Time: 0.571 ms
db2022=# update test set value = 12 where id = 1;
UPDATE 1
Time: 0.726 ms
db2022=# update test set value = 18 where id = 2;
UPDATE 1
Time: 0.553 ms
db2022=# commit;
COMMIT
Time: 33.049 ms
5. 在 T1 中执行以下语句,查询表test中id为2的记录
db2022=# select * from test where id = 2;
id | value
----+-------
2 | 18
(1 row)
Time: 0.572 ms
db2022=# select * from test;
id | value
----+-------
1 | 12
2 | 18
(2 rows)
Time: 0.580 ms
T1 分别读取了 id = 1, 2 的两次,结果为(1,10),(2,18)
,但这并不存在于数据库中。
repeatable read 隔离级别可以避免 Predicate-Many-Preceders 异常
6. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 1.196 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 181.163 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 0.920 ms
db2022=# begin;
WARNING: there is already a transaction in progress
BEGIN
Time: 0.345 ms
db2022=# set transaction isolation level repeatable read;
ERROR: SET TRANSACTION ISOLATION LEVEL must be called before any query
Time: 498.818 ms
9. 在 T1 中执行以下语句,查询test表中数据
db2022=# select * from test where value = 30;
id | value
----+-------
(0 rows)
Time: 0.891 ms
10. 在 T2 中执行以下语句,向test表中插入数据,然后提交
db2022=# insert into test (id, value) values(3, 30);
INSERT 0 1
Time: 0.636 ms
db2022=# commit;
COMMIT
Time: 36.986 ms
1. 在 T1 中执行以下语句,查询test表中数据
db2022=# select * from test where value % 3 = 0;
id | value
----+-------
(0 rows)
Time: 0.702 ms
db2022=# commit;
COMMIT
Time: 0.442 ms
两次查询结果均相同。
repeatable read 隔离级别可以避免 Predicate-Many-Preceders for write
predicates 异常
2. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 143.159 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 279.746 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 117.401 ms
db2022=# begin;
BEGIN
Time: 0.249 ms
db2022=# set transaction isolation level repeatable read;
SET
Time: 0.372 ms
5. 在 T1 中执行以下语句,更新表test中的数据
db2022=# update test set value = value + 10;
UPDATE 2
Time: 0.639 ms
6. 在 T2 中执行以下语句,删除表test中value为20的记录
db2022=# delete from test where value = 20;
阻塞
7. 在 T1 中提交事务,T2 会报错
db2022=# delete from test where value = 20;
ERROR: could not serialize access due to concurrent update
Time: 4675.140 ms
8. 在 T2 中执行以下语句,撤销事务
db2022=# abort;
ROLLBACK
Time: 0.325 ms
禁止了 T2 修改 T1 中修改的记录,就不会有“T2 删除了所有 value=20 的记录,但删除后依旧能查到 value=20 的记录”的问题。
repeatable read 隔离级别可以避免 Lost Update 异常
9. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 151.185 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 218.647 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 66.391 ms
db2022=# begin;
BEGIN
Time: 0.256 ms
db2022=# set transaction isolation level repeatable read;
SET
Time: 0.424 ms
2. 在 T1 中执行以下语句,查询表test中id为1的记录
db2022=# select * from test where id = 1;
id | value
----+-------
1 | 10
(1 row)
Time: 0.785 ms
3. 在 T2 中执行以下语句,查询表test中id为1的记录
db2022=# select * from test where id = 1;
id | value
----+-------
1 | 10
(1 row)
Time: 0.715 ms
4. 在 T1 中执行以下语句,更新表test中id为1的记录
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.655 ms
5. 在 T2 中执行以下语句,更新表test中id为1的记录
db2022=# update test set value = 12 where id = 1;
阻塞
6. 在 T1 中提交事务,T2 报错:
db2022=# update test set value = 12 where id = 1;
ERROR: could not serialize access due to concurrent update
Time: 11860.582 ms
7. 在 T2 中撤销事务
repeatable read 隔离级别可以避免 Read Skew 异常(1)
8. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 145.764 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 212.357 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 66.831 ms
db2022=# begin;
BEGIN
Time: 0.228 ms
db2022=# set transaction isolation level repeatable read;
SET
Time: 0.388 ms
1. 在 T1 中执行以下语句,查询表test中id为1的记录
db2022=# select * from test where id = 1;
id | value
----+-------
1 | 10
(1 row)
Time: 0.577 ms
2. 在 T2 中执行以下语句,查询并更新表test中的记录,然后提交事务
db2022=# select * from test where id = 1; --返回(1,10)
id | value
----+-------
1 | 10
(1 row)
Time: 0.814 ms
db2022=# select * from test where id = 2; --返回(2,20)
id | value
----+-------
2 | 20
(1 row)
Time: 0.472 ms
db2022=# update test set value = 12 where id = 1;
UPDATE 1
Time: 0.553 ms
db2022=# update test set value = 18 where id = 2;
UPDATE 1
Time: 0.493 ms
db2022=# commit;
COMMIT
Time: 33.217 ms
3. 在 T1 中执行以下语句,查询表test中id为2的记录
db2022=# select * from test where id = 2; --返回(2,20)
id | value
----+-------
2 | 20
(1 row)
Time: 0.646 ms
db2022=# commit;
COMMIT
Time: 0.552 ms
T1 的两次读均没有被 T2 影响,即可重复读。
repeatable read 隔离级别可以避免 Read Skew 异常(2)
4. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 143.054 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 251.579 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 66.175 ms
db2022=# begin;
BEGIN
Time: 0.247 ms
db2022=# set transaction isolation level repeatable read;
SET
Time: 0.342 ms
7. 在 T1 中执行以下语句,查询表test中的记录
db2022=# select * from test where value % 5 = 0;
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 0.722 ms
8. 在 T2 中执行以下语句,更新表test中的记录,然后提交事务
db2022=# update test set value = 12 where value = 10;
UPDATE 1
Time: 0.882 ms
db2022=# commit;
COMMIT
Time: 52.269 ms
9. 在 T1 中执行以下语句,查询表test中的记录
db2022=# select * from test where value % 3 = 0; --返回空集
id | value
----+-------
(0 rows)
Time: 0.685 ms
db2022=# commit;
COMMIT
Time: 0.452 ms
两次结果依旧一致,即可重复读。
repeatable read 隔离级别可以避免 Read Skew 异常(3)
10. 在 T1 中重置测试数据表
在 T1 2 中设置当前会话的事务隔离级别
3. 在 T1 中执行以下语句,查询表test中id为1的记录
db2022=# select * from test where id = 1;
id | value
----+-------
1 | 10
(1 row)
Time: 0.734 ms
4. 在 T2 中执行以下语句,查询并更新表test中的记录,然后提交事务
db2022=# select * from test; --返回(1,10),(2,20)
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 0.733 ms
db2022=# update test set value = 12 where id = 1;
UPDATE 1
Time: 0.530 ms
db2022=# update test set value = 18 where id = 2;
UPDATE 1
Time: 0.581 ms
db2022=# commit;
COMMIT
Time: 36.597 ms
5. 在 T1 中执行以下语句,删除表test中value为20的记录
db2022=# delete from test where value = 20;
ERROR: could not serialize access due to concurrent update
Time: 3.319 ms
db2022=# abort;
ROLLBACK
Time: 0.259 ms
repeatable read 隔离级别不能避免 Write Skew 异常
6. 在 T1 中重置测试数据表
在 T1 2 中设置当前会话的事务隔离级别
9. 在 T1 中执行以下语句,查询表test中的记录
db2022=# select * from test where id in (1,2);
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 1.076 ms
10. 在 T2 中执行以下语句,查询表test中的记录
db2022=# select * from test where id in (1,2);
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 1.131 ms
1. 在 T1 中执行以下语句,更新表test中id为1的记录
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.735 ms
2. 在 T2 中执行以下语句,更新表test中id为2的记录
db2022=# update test set value = 21 where id = 2;
UPDATE 1
Time: 0.526 ms
3. 在 T1 2 中执行以下语句,提交事务
db2022=# commit;
COMMIT
Time: 116.664 ms
db2022=# select * from test;
id | value
----+-------
1 | 11
2 | 21
(2 rows)
Time: 0.619 ms
T1 T2 均没注意到对方的修改,并分别作出了(不相交但可能重复的)修改。
repeatable read 隔离级别不能避免 Anti-Dependency Cycles 异常
5. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
8. 在 T1 中执行以下语句,查询表test中的记录
db2022=# select * from test where value % 3 = 0;
id | value
----+-------
(0 rows)
Time: 0.786 ms
9. 在 T2 中执行以下语句,查询表test中的记录
db2022=# select * from test where value % 3 = 0;
id | value
----+-------
(0 rows)
Time: 0.914 ms
10. 在 T1 中执行以下语句,向表test中插入新记录
db2022=# insert into test (id, value) values(3, 30);
INSERT 0 1
Time: 0.818 ms
1. 在 T2 中执行以下语句,向表test中插入新记录
db2022=# insert into test (id, value) values(4, 42);
INSERT 0 1
Time: 0.467 ms
2. 在 T1 2 中提交事务
4. 在 T1 或 T2 中执行以下语句
db2022=# select * from test where value % 3 = 0;
id | value
----+-------
3 | 30
4 | 42
(2 rows)
Time: 0.689 ms
类似写偏斜。
serializable 隔离级别不能避免 Write Skew 异常
5. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
db2022=# drop table test;
DROP TABLE
Time: 142.564 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 223.745 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 366.140 ms
db2022=# begin;
BEGIN
Time: 0.344 ms
db2022=# set transaction isolation level serializable;
SET
Time: 0.381 ms
8. 在 T1 中执行以下语句,查询表test中的记录
db2022=# select * from test where id in (1,2);
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 0.769 ms
9. 在 T2 中执行以下语句,查询表test中的记录
db2022=# select * from test where id in (1,2);
id | value
----+-------
1 | 10
2 | 20
(2 rows)
Time: 0.849 ms
10. 在 T1 中执行以下语句,更新表test中id为1的记录
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.760 ms
1. 在 T2 中执行以下语句,更新表test中id为2的记录
db2022=# update test set value = 21 where id = 2;
UPDATE 1
Time: 0.536 ms
2. 在 T1 2 中执行以下语句,提交事务
db2022=# commit;
COMMIT
Time: 116.416 ms
db2022=# select * from test;
id | value
----+-------
1 | 11
2 | 21
(2 rows)
Time: 0.568 ms
openGauss的serializable等价于repeatable read,不能避免写偏斜。
在新版本的PostgreSQL中,serializable可以避免Write Skew(报错"ERROR: could not serialize access due to read/write dependencies among transactions")。
serializable 隔离级别不能避免 Anti-Dependency Cycles 异常
4. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别
7. 在 T1 中执行以下语句,查询表test中的记录
db2022=# select * from test where value % 3 = 0;
id | value
----+-------
(0 rows)
Time: 0.908 ms
8. 在 T2 中执行以下语句,查询表test中的记录
db2022=# select * from test where value % 3 = 0;
id | value
----+-------
(0 rows)
Time: 0.631 ms
9. 在 T1 中执行以下语句,向表test中插入新记录
db2022=# insert into test (id, value) values(3, 30);
INSERT 0 1
Time: 0.519 ms
10. 在 T2 中执行以下语句,向表test中插入新记录
db2022=# insert into test (id, value) values(4, 42);
INSERT 0 1
Time: 0.781 ms
1. 在 T1 2 中执行以下语句,提交事务
db2022=# commit;
COMMIT
Time: 108.364 ms
db2022=# select * from test;
id | value
----+-------
1 | 10
2 | 20
3 | 30
4 | 42
(4 rows)
Time: 0.833 ms
openGauss的serializable等价于repeatable read。
在新版本的PostgreSQL中,serializable可以避免Anti-Dependency Cycles(报错"ERROR: could not serialize access due to read/write dependencies among transactions")。
1. 在 T1 中执行以下语句,创建数据表test
db2022=# drop table if exists test;
DROP TABLE
Time: 146.183 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 186.755 ms
2. 在 T1 中执行以下语句,查询当前事务ID,然后插入数据
db2022=# begin;
BEGIN
Time: 0.487 ms
db2022=# select txid_current();
txid_current
--------------
14727
(1 row)
Time: 119.613 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 1.225 ms
db2022=# insert into test (id, value) values (3, 30), (4, 40);
INSERT 0 2
Time: 0.565 ms
3. 在 T1 中执行以下语句,查询表test中的记录(包含隐藏字段)
db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
xmin | xmax | ctid | cmin | cmax | id | value
-------+------+-------+------+------+----+-------
14727 | 0 | (0,1) | 0 | 0 | 1 | 10
14727 | 0 | (0,2) | 0 | 0 | 2 | 20
14727 | 0 | (0,3) | 1 | 1 | 3 | 30
14727 | 0 | (0,4) | 1 | 1 | 4 | 40
(4 rows)
Time: 0.924 ms
4. 在 T1 中执行以下语句,更新数据后查询表test中的记录(包含隐藏字段)
db2022=# update test set value = 11 where id = 1;
UPDATE 1
Time: 0.719 ms
db2022=# delete from test where id = 4;
DELETE 1
Time: 0.468 ms
db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
xmin | xmax | ctid | cmin | cmax | id | value
-------+------+-------+------+------+----+-------
14727 | 0 | (0,2) | 0 | 0 | 2 | 20
14727 | 0 | (0,3) | 1 | 1 | 3 | 30
14727 | 0 | (0,5) | 2 | 2 | 1 | 11
(3 rows)
Time: 0.879 ms
db2022=# commit;
COMMIT
Time: 27.930 ms
ctid 为插入这条记录的 cid。
5. 在 T1 中执行以下语句,更新数据后查询表test中的记录(包含隐藏字段)
db2022=# begin;
BEGIN
Time: 0.308 ms
db2022=# select txid_current();
txid_current
--------------
14728
(1 row)
Time: 0.444 ms
db2022=# update test set value = 21 where id = 2;
UPDATE 1
Time: 0.578 ms
db2022=# delete from test where id = 3;
DELETE 1
Time: 0.497 ms
db2022=# update test set value = 22 where id = 2;
UPDATE 1
Time: 0.543 ms
db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
xmin | xmax | ctid | cmin | cmax | id | value
-------+------+-------+------+------+----+-------
14727 | 0 | (0,5) | 2 | 2 | 1 | 11
14728 | 0 | (0,7) | 2 | 2 | 2 | 22
(2 rows)
Time: 0.649 ms
db2022=# abort;
ROLLBACK
Time: 0.424 ms
db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
xmin | xmax | ctid | cmin | cmax | id | value
-------+-------+-------+------+------+----+-------
14727 | 14728 | (0,2) | 0 | 0 | 2 | 20
14727 | 14728 | (0,3) | 1 | 1 | 3 | 30
14727 | 0 | (0,5) | 2 | 2 | 1 | 11
(3 rows)
Time: 0.678 ms
即使abort,xmax还是相应更新了?
1. 在 T1 中执行以下语句,创建数据表test并插入数据
db2022=# drop table if exists test;
DROP TABLE
Time: 151.743 ms
db2022=# create table test (id int primary key, value int);
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
CREATE TABLE
Time: 240.563 ms
db2022=# insert into test (id, value) values (1, 10), (2, 20);
INSERT 0 2
Time: 131.728 ms
2. 在 T1 中执行以下语句,设置事务隔离级别,查询事务ID和快照
db2022=# begin;
BEGIN
Time: 0.344 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.302 ms
db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
--------------+-----------------------+-------+------+-------+------+------+----+-------
14734 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
14734 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
(2 rows)
Time: 0.966 ms
在 T2 中执行以下语句,设置事务隔离级别,查询事务ID和快照
db2022=# begin;
BEGIN
Time: 0.318 ms
db2022=# set transaction isolation level read committed;
SET
Time: 0.289 ms
db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
--------------+-----------------------+-------+------+-------+------+------+----+-------
14735 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
14735 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
(2 rows)
Time: 0.997 ms
3. 在 T3 中执行以下语句,设置事务隔离级别,查询事务ID和快照
db2022=# begin;
BEGIN
db2022=# set transaction isolation level repeatable read;
SET
db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
--------------+-----------------------+-------+------+-------+------+------+----+-------
14736 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
14736 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
(2 rows)
4. 在 T1 中提交事务
5. 在 T2 中执行以下语句,查询事务ID和快照
db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
--------------+-----------------------+-------+------+-------+------+------+----+-------
14735 | 14735:14735: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
14735 | 14735:14735: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
(2 rows)
Time: 0.877 ms
6. 在 T3 中执行以下语句,查询事务ID和快照
db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
--------------+-----------------------+-------+------+-------+------+------+----+-------
14736 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
14736 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
(2 rows)
说明:提交读每条语句都获取快照,可重复读只在获得txid时生成快照