[关闭]
@SovietPower 2022-06-05T22:26:31.000000Z 字数 22742 阅读 953

数据库系统 实验7

DB



1-10

1. 在Dokcer环境中启动之前实验创建的openGauss容器。

2. 连接到数据库db2022(将该会话记作 T1 )

  1. PS H:\> docker exec -it opengauss3 bash
  2. root@97375c3acbd1:/# su omm
  3. omm@97375c3acbd1:/$ gsql -d db2022 -r

3. 在 T1 中执行以下SQL语句,创建用于事务 隔离级别(Isolation Level) 测试的数据表

  1. db2022=# create table test (id int primary key, value int);
  2. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  3. CREATE TABLE
  4. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  5. INSERT 0 2

4. 在 T1 中执行以下语句,查看并设置当前会话的参数
lockwait_timeout:控制单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
update_lockwait_timeout:允许并发更新参数开启情况下,该参数控制并发更新同一行时单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。
延长update_lockwait_timeout,则多个事务并行执行时等待锁的时间更长,方便输入语句测试。

  1. db2022=# select current_setting('transaction_isolation');
  2. current_setting
  3. -----------------
  4. read committed
  5. (1 row)
  6. db2022=# show update_lockwait_timeout;
  7. update_lockwait_timeout
  8. -------------------------
  9. 2min
  10. (1 row)
  11. db2022=# set update_lockwait_timeout to 1200000;
  12. SET
  13. db2022=# show update_lockwait_timeout;
  14. update_lockwait_timeout
  15. -------------------------
  16. 20min
  17. (1 row)
  18. db2022=# \timing
  19. Timing is on.

5. 打开另一个PowerShell窗口,连接到数据库db2022(将该会话记作 T2 ),执行

  1. db2022=# set update_lockwait_timeout to 1200000;
  2. SET
  3. db2022=# \timing
  4. Timing is on.

read committed 隔离级别可以避免 Write Cycles 异常
Read Commited保证:
读数据时只能读到已经提交了的数据 (没有脏读)
写数据时只能覆盖已经提交了的数据 (没有脏写)

6.7. 在 T1,T2 中都执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.315 ms
  4. db2022=# set transaction isolation level read committed;
  5. SET
  6. Time: 0.446 ms

8. 在 T1 中执行以下语句,对test表中id=1的记录进行更新

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.730 ms

9. 在 T2 中执行以下语句,同样对test表中id=1的记录进行更新

  1. db2022=# update test set value = 12 where id = 1;
  2. 此时,T2中的事务被阻塞
  3. UPDATE 1
  4. Time: 44844.698 ms

10. 在 T1 中执行以下语句,对test表中id=2的记录进行更新,然后提交事务

  1. db2022=# update test set value = 21 where id = 2;
  2. UPDATE 1
  3. Time: 0.663 ms
  4. db2022=# commit;
  5. COMMIT
  6. Time: 411.061 ms
  7. 此时结束对T2中事务的阻塞

11-20

1. 在 T1 中执行以下语句,查询test表中的数据
此时 T2 修改未提交

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 11
  5. 2 | 21
  6. (2 rows)
  7. Time: 0.615 ms

2. 在 T2 中执行以下语句,对test表中id=2的记录进行更新,然后提交事务

  1. db2022=# update test set value = 22 where id = 2;
  2. UPDATE 1
  3. Time: 0.521 ms
  4. db2022=# commit;
  5. COMMIT
  6. Time: 294.785 ms

3. 在 T2 中执行以下语句,查询test表中的数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 12
  5. 2 | 22
  6. (2 rows)
  7. Time: 0.903 ms

read committed 隔离级别可以避免 Aborted Reads 异常
4. 在 T1 中执行以下语句,重置测试数据表

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 1656.834 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 9758.841 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 3422.961 ms

5. 在 T1 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.375 ms
  4. db2022=# set transaction isolation level read committed;
  5. SET
  6. Time: 0.368 ms

6. 在 T2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.575 ms
  4. db2022=# set transaction isolation level read committed;
  5. SET
  6. Time: 0.459 ms

7. 在 T1 中执行以下语句,对test表中id=1的记录进行更新

  1. db2022=# update test set value = 101 where id = 1;
  2. UPDATE 1
  3. Time: 0.956 ms

8. 在 T2 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 1.169 ms

9. 在 T1 中执行以下语句,撤销事务

  1. db2022=# abort;
  2. ROLLBACK
  3. Time: 0.666 ms

10. 在 T2 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 0.776 ms
  8. db2022=# commit;
  9. COMMIT
  10. Time: 0.526 ms

21-30

read committed 隔离级别可以避免 intermediate Reads 异常
1. 在 T1 中执行以下语句,重置测试数据表

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 3017.035 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 11315.591 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 2152.651 ms

2. 在 T1 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.284 ms
  4. db2022=# set transaction isolation level read committed;
  5. SET
  6. Time: 0.495 ms

3. 在 T2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.389 ms
  4. db2022=# set transaction isolation level read committed;
  5. SET
  6. Time: 0.415 ms

4. 在 T1 中执行以下语句,对test表中id=1的记录进行更新

  1. db2022=# update test set value = 101 where id = 1;
  2. UPDATE 1
  3. Time: 0.601 ms

5. 在 T2 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 0.716 ms

6. 在 T1 中执行以下语句,再次对test表中id=1的记录进行更新,然后提交

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.577 ms
  4. db2022=# commit;
  5. COMMIT
  6. Time: 2151.811 ms

7. 在 T2 中执行以下语句,再次查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 2 | 20
  5. 1 | 11
  6. (2 rows)
  7. Time: 0.513 ms

read committed 隔离级别可以避免 Circular Information Flow 异常
8. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. db2022=# create table test (id int primary key, value int);
  4. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  5. CREATE TABLE
  6. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  7. INSERT 0 2
  8. db2022=# begin;
  9. BEGIN
  10. db2022=# set transaction isolation level read committed;
  11. SET

31-40

1. 在 T1 中执行以下语句,对test表中id=1的记录进行更新

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1

2. 在 T2 中执行以下语句,对test表中id=2的记录进行更新

  1. db2022=# update test set value = 22 where id = 2;
  2. UPDATE 1

3. 在 T1 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 2 | 20
  5. 1 | 11
  6. (2 rows)

4. 在 T2 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 22
  6. (2 rows)

5. 在 T1 中执行以下语句,提交事务

  1. db2022=# commit
  2. db2022-# ;
  3. COMMIT

6. 在 T2 中执行以下语句,提交事务

  1. db2022=# commit;
  2. COMMIT
  3. db2022=# select * from test;
  4. id | value
  5. ----+-------
  6. 1 | 11
  7. 2 | 22
  8. (2 rows)

read committed 隔离级别可以避免 Observed Transaction Vanishes 异常
7. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. db2022=# create table test (id int primary key, value int);
  4. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  5. CREATE TABLE
  6. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  7. INSERT 0 2
  8. db2022=# begin;
  9. BEGIN
  10. db2022=# set transaction isolation level read committed;
  11. SET

10. 打开一个新的PowerShell窗口,连接到数据库db2022(将该会话记作 T3 ),执行

  1. db2022=# set update_lockwait_timeout to 1200000;
  2. SET
  3. db2022=# \timing
  4. Timing is on.
  5. db2022=# begin;
  6. BEGIN
  7. Time: 0.234 ms
  8. db2022=# set transaction isolation level read committed;
  9. SET
  10. Time: 0.431 ms

41-50

1. 在 T1 中执行以下语句,对test表中记录进行更新

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.585 ms
  4. db2022=# update test set value = 19 where id = 2;
  5. UPDATE 1
  6. Time: 0.509 ms

在 T2 中执行以下语句,对test表中记录进行更新

  1. db2022=# update test set value = 12 where id = 1;
  2. 阻塞

2. 在 T1 中执行以下语句,提交事务

  1. db2022=# commit;
  2. COMMIT
  3. Time: 106.829 ms
  4. T2结束阻塞

3. 在 T3 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 11
  5. 2 | 19
  6. (2 rows)
  7. Time: 0.971 ms

4. 在 T2 中执行以下语句,对test表中记录进行更新

  1. db2022=# update test set value = 18 where id = 2;
  2. UPDATE 1
  3. Time: 0.562 ms

5. 在 T3 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 11
  5. 2 | 19
  6. (2 rows)
  7. Time: 0.560 ms

6. 在 T2 中执行以下语句,提交事务

  1. db2022=# commit;
  2. COMMIT
  3. Time: 118.936 ms

7. 在 T3 中执行以下语句,查询test表中数据

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 1 | 12
  5. 2 | 18
  6. (2 rows)
  7. Time: 0.778 ms

提交的事务不会丢失。

read committed 隔离级别不能避免 Predicate-Many-Preceders 异常
8. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 6818.855 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 211.857 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 135.669 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.283 ms
  14. db2022=# set transaction isolation level read committed;
  15. SET
  16. Time: 0.323 ms

51-60

1. 在 T1 中执行以下语句,查询test表中数据

  1. db2022=# select * from test where value = 30;
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.839 ms

2. 在 T2 中执行以下语句,向test表中插入数据,然后提交

  1. db2022=# insert into test (id, value) values(3, 30);
  2. INSERT 0 1
  3. Time: 0.656 ms
  4. db2022=# commit;
  5. COMMIT
  6. Time: 36.350 ms

3. 在 T1 中执行以下语句,查询test表中数据

  1. db2022=# select * from test where value % 3 = 0;
  2. id | value
  3. ----+-------
  4. 3 | 30
  5. (1 row)
  6. Time: 1.058 ms
  7. db2022=# commit
  8. db2022-# ;
  9. COMMIT
  10. Time: 0.319 ms

第二次查询的结果并不在第一次中,不可重复读。

read committed 隔离级别不能避免 Predicate-Many-Preceders for write
predicates 异常

4. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 136.073 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 229.252 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 67.571 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.325 ms
  14. db2022=# set transaction isolation level read committed;
  15. SET
  16. Time: 0.371 ms

7. 在 T1 中执行以下语句,更新表test中的数据

  1. db2022=# update test set value = value + 10;
  2. UPDATE 2
  3. Time: 1.114 ms

8. 在 T2 中执行以下语句,删除表test中value为20的记录

  1. db2022=# delete from test where value = 20;
  2. 阻塞

9. 在 T1 中提交事务

10. 在 T2 中执行以下语句,查询表test中value为20的记录

  1. db2022=# select * from test where value = 20;
  2. id | value
  3. ----+-------
  4. 1 | 20
  5. (1 row)
  6. Time: 0.805 ms

T2 删除了所有 value=20 的记录,但删除后依旧能查到 value=20 的记录。

61-70

read committed 隔离级别不能避免 Lost Update 异常
1. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 155.979 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 690.676 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 66.225 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.259 ms
  14. db2022=# set transaction isolation level read committed;
  15. SET
  16. Time: 0.453 ms

4. 在 T1 中执行以下语句,查询表test中id为1的记录

  1. db2022=# select * from test where id = 1;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.572 ms

5. 在 T2 中执行以下语句,查询表test中id为1的记录

  1. db2022=# select * from test where id = 1;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.942 ms

6. 在 T1 中执行以下语句,更新表test中id为1的记录

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.832 ms

7. 在 T2 中执行以下语句,更新表test中id为1的记录

  1. db2022=# update test set value = 12 where id = 1;
  2. 阻塞

8. 在 T1 2 中提交事务

  1. db2022=# select * from test;
  2. id | value
  3. ----+-------
  4. 2 | 20
  5. 1 | 12
  6. (2 rows)
  7. Time: 0.777 ms

T1 的更新丢失。

read committed 隔离级别不能避免 Read Skew 异常
10. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 145.889 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 268.693 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 56.577 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.309 ms
  14. db2022=# set transaction isolation level read committed;
  15. SET
  16. Time: 0.480 ms

71-80

3. 在 T1 中执行以下语句,查询表test中id为1的记录

  1. db2022=# select * from test where id = 1;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.623 ms

4. 在 T2 中执行以下语句,查询并更新表test中的记录,然后提交事务

  1. db2022=# select * from test where id = 1; --返回(1,10)
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.761 ms
  7. db2022=# select * from test where id = 2; --返回(2,20)
  8. id | value
  9. ----+-------
  10. 2 | 20
  11. (1 row)
  12. Time: 0.571 ms
  13. db2022=# update test set value = 12 where id = 1;
  14. UPDATE 1
  15. Time: 0.726 ms
  16. db2022=# update test set value = 18 where id = 2;
  17. UPDATE 1
  18. Time: 0.553 ms
  19. db2022=# commit;
  20. COMMIT
  21. Time: 33.049 ms

5. 在 T1 中执行以下语句,查询表test中id为2的记录

  1. db2022=# select * from test where id = 2;
  2. id | value
  3. ----+-------
  4. 2 | 18
  5. (1 row)
  6. Time: 0.572 ms
  7. db2022=# select * from test;
  8. id | value
  9. ----+-------
  10. 1 | 12
  11. 2 | 18
  12. (2 rows)
  13. Time: 0.580 ms

T1 分别读取了 id = 1, 2 的两次,结果为(1,10),(2,18),但这并不存在于数据库中。

repeatable read 隔离级别可以避免 Predicate-Many-Preceders 异常
6. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 1.196 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 181.163 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 0.920 ms
  11. db2022=# begin;
  12. WARNING: there is already a transaction in progress
  13. BEGIN
  14. Time: 0.345 ms
  15. db2022=# set transaction isolation level repeatable read;
  16. ERROR: SET TRANSACTION ISOLATION LEVEL must be called before any query
  17. Time: 498.818 ms

9. 在 T1 中执行以下语句,查询test表中数据

  1. db2022=# select * from test where value = 30;
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.891 ms

10. 在 T2 中执行以下语句,向test表中插入数据,然后提交

  1. db2022=# insert into test (id, value) values(3, 30);
  2. INSERT 0 1
  3. Time: 0.636 ms
  4. db2022=# commit;
  5. COMMIT
  6. Time: 36.986 ms

81-90

1. 在 T1 中执行以下语句,查询test表中数据

  1. db2022=# select * from test where value % 3 = 0;
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.702 ms
  6. db2022=# commit;
  7. COMMIT
  8. Time: 0.442 ms

两次查询结果均相同。

repeatable read 隔离级别可以避免 Predicate-Many-Preceders for write
predicates 异常

2. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 143.159 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 279.746 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 117.401 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.249 ms
  14. db2022=# set transaction isolation level repeatable read;
  15. SET
  16. Time: 0.372 ms

5. 在 T1 中执行以下语句,更新表test中的数据

  1. db2022=# update test set value = value + 10;
  2. UPDATE 2
  3. Time: 0.639 ms

6. 在 T2 中执行以下语句,删除表test中value为20的记录

  1. db2022=# delete from test where value = 20;
  2. 阻塞

7. 在 T1 中提交事务,T2 会报错

  1. db2022=# delete from test where value = 20;
  2. ERROR: could not serialize access due to concurrent update
  3. Time: 4675.140 ms

8. 在 T2 中执行以下语句,撤销事务

  1. db2022=# abort;
  2. ROLLBACK
  3. Time: 0.325 ms

禁止了 T2 修改 T1 中修改的记录,就不会有“T2 删除了所有 value=20 的记录,但删除后依旧能查到 value=20 的记录”的问题。

repeatable read 隔离级别可以避免 Lost Update 异常
9. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 151.185 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 218.647 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 66.391 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.256 ms
  14. db2022=# set transaction isolation level repeatable read;
  15. SET
  16. Time: 0.424 ms

91-100

2. 在 T1 中执行以下语句,查询表test中id为1的记录

  1. db2022=# select * from test where id = 1;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.785 ms

3. 在 T2 中执行以下语句,查询表test中id为1的记录

  1. db2022=# select * from test where id = 1;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.715 ms

4. 在 T1 中执行以下语句,更新表test中id为1的记录

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.655 ms

5. 在 T2 中执行以下语句,更新表test中id为1的记录

  1. db2022=# update test set value = 12 where id = 1;
  2. 阻塞

6. 在 T1 中提交事务,T2 报错:

  1. db2022=# update test set value = 12 where id = 1;
  2. ERROR: could not serialize access due to concurrent update
  3. Time: 11860.582 ms

7. 在 T2 中撤销事务

repeatable read 隔离级别可以避免 Read Skew 异常(1)
8. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 145.764 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 212.357 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 66.831 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.228 ms
  14. db2022=# set transaction isolation level repeatable read;
  15. SET
  16. Time: 0.388 ms

101-110

1. 在 T1 中执行以下语句,查询表test中id为1的记录

  1. db2022=# select * from test where id = 1;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.577 ms

2. 在 T2 中执行以下语句,查询并更新表test中的记录,然后提交事务

  1. db2022=# select * from test where id = 1; --返回(1,10)
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.814 ms
  7. db2022=# select * from test where id = 2; --返回(2,20)
  8. id | value
  9. ----+-------
  10. 2 | 20
  11. (1 row)
  12. Time: 0.472 ms
  13. db2022=# update test set value = 12 where id = 1;
  14. UPDATE 1
  15. Time: 0.553 ms
  16. db2022=# update test set value = 18 where id = 2;
  17. UPDATE 1
  18. Time: 0.493 ms
  19. db2022=# commit;
  20. COMMIT
  21. Time: 33.217 ms

3. 在 T1 中执行以下语句,查询表test中id为2的记录

  1. db2022=# select * from test where id = 2; --返回(2,20)
  2. id | value
  3. ----+-------
  4. 2 | 20
  5. (1 row)
  6. Time: 0.646 ms
  7. db2022=# commit;
  8. COMMIT
  9. Time: 0.552 ms

T1 的两次读均没有被 T2 影响,即可重复读。

repeatable read 隔离级别可以避免 Read Skew 异常(2)
4. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 143.054 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 251.579 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 66.175 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.247 ms
  14. db2022=# set transaction isolation level repeatable read;
  15. SET
  16. Time: 0.342 ms

7. 在 T1 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where value % 5 = 0;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 0.722 ms

8. 在 T2 中执行以下语句,更新表test中的记录,然后提交事务

  1. db2022=# update test set value = 12 where value = 10;
  2. UPDATE 1
  3. Time: 0.882 ms
  4. db2022=# commit;
  5. COMMIT
  6. Time: 52.269 ms

9. 在 T1 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where value % 3 = 0; --返回空集
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.685 ms
  6. db2022=# commit;
  7. COMMIT
  8. Time: 0.452 ms

两次结果依旧一致,即可重复读。

repeatable read 隔离级别可以避免 Read Skew 异常(3)
10. 在 T1 中重置测试数据表
在 T1 2 中设置当前会话的事务隔离级别

111-120

3. 在 T1 中执行以下语句,查询表test中id为1的记录

  1. db2022=# select * from test where id = 1;
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. (1 row)
  6. Time: 0.734 ms

4. 在 T2 中执行以下语句,查询并更新表test中的记录,然后提交事务

  1. db2022=# select * from test; --返回(1,10),(2,20)
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 0.733 ms
  8. db2022=# update test set value = 12 where id = 1;
  9. UPDATE 1
  10. Time: 0.530 ms
  11. db2022=# update test set value = 18 where id = 2;
  12. UPDATE 1
  13. Time: 0.581 ms
  14. db2022=# commit;
  15. COMMIT
  16. Time: 36.597 ms

5. 在 T1 中执行以下语句,删除表test中value为20的记录

  1. db2022=# delete from test where value = 20;
  2. ERROR: could not serialize access due to concurrent update
  3. Time: 3.319 ms
  4. db2022=# abort;
  5. ROLLBACK
  6. Time: 0.259 ms

repeatable read 隔离级别不能避免 Write Skew 异常
6. 在 T1 中重置测试数据表
在 T1 2 中设置当前会话的事务隔离级别

9. 在 T1 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where id in (1,2);
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 1.076 ms

10. 在 T2 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where id in (1,2);
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 1.131 ms

121-130

1. 在 T1 中执行以下语句,更新表test中id为1的记录

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.735 ms

2. 在 T2 中执行以下语句,更新表test中id为2的记录

  1. db2022=# update test set value = 21 where id = 2;
  2. UPDATE 1
  3. Time: 0.526 ms

3. 在 T1 2 中执行以下语句,提交事务

  1. db2022=# commit;
  2. COMMIT
  3. Time: 116.664 ms
  4. db2022=# select * from test;
  5. id | value
  6. ----+-------
  7. 1 | 11
  8. 2 | 21
  9. (2 rows)
  10. Time: 0.619 ms

T1 T2 均没注意到对方的修改,并分别作出了(不相交但可能重复的)修改。

repeatable read 隔离级别不能避免 Anti-Dependency Cycles 异常
5. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

8. 在 T1 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where value % 3 = 0;
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.786 ms

9. 在 T2 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where value % 3 = 0;
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.914 ms

10. 在 T1 中执行以下语句,向表test中插入新记录

  1. db2022=# insert into test (id, value) values(3, 30);
  2. INSERT 0 1
  3. Time: 0.818 ms

131-140

1. 在 T2 中执行以下语句,向表test中插入新记录

  1. db2022=# insert into test (id, value) values(4, 42);
  2. INSERT 0 1
  3. Time: 0.467 ms

2. 在 T1 2 中提交事务

4. 在 T1 或 T2 中执行以下语句

  1. db2022=# select * from test where value % 3 = 0;
  2. id | value
  3. ----+-------
  4. 3 | 30
  5. 4 | 42
  6. (2 rows)
  7. Time: 0.689 ms

类似写偏斜。

serializable 隔离级别不能避免 Write Skew 异常
5. 在 T1 中执行以下语句,重置测试数据表
在 T1 2 中执行以下语句,设置当前会话的事务隔离级别

  1. db2022=# drop table test;
  2. DROP TABLE
  3. Time: 142.564 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 223.745 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 366.140 ms
  11. db2022=# begin;
  12. BEGIN
  13. Time: 0.344 ms
  14. db2022=# set transaction isolation level serializable;
  15. SET
  16. Time: 0.381 ms

8. 在 T1 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where id in (1,2);
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 0.769 ms

9. 在 T2 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where id in (1,2);
  2. id | value
  3. ----+-------
  4. 1 | 10
  5. 2 | 20
  6. (2 rows)
  7. Time: 0.849 ms

10. 在 T1 中执行以下语句,更新表test中id为1的记录

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.760 ms

141-150

1. 在 T2 中执行以下语句,更新表test中id为2的记录

  1. db2022=# update test set value = 21 where id = 2;
  2. UPDATE 1
  3. Time: 0.536 ms

2. 在 T1 2 中执行以下语句,提交事务

  1. db2022=# commit;
  2. COMMIT
  3. Time: 116.416 ms
  4. db2022=# select * from test;
  5. id | value
  6. ----+-------
  7. 1 | 11
  8. 2 | 21
  9. (2 rows)
  10. 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中的记录

  1. db2022=# select * from test where value % 3 = 0;
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.908 ms

8. 在 T2 中执行以下语句,查询表test中的记录

  1. db2022=# select * from test where value % 3 = 0;
  2. id | value
  3. ----+-------
  4. (0 rows)
  5. Time: 0.631 ms

9. 在 T1 中执行以下语句,向表test中插入新记录

  1. db2022=# insert into test (id, value) values(3, 30);
  2. INSERT 0 1
  3. Time: 0.519 ms

10. 在 T2 中执行以下语句,向表test中插入新记录

  1. db2022=# insert into test (id, value) values(4, 42);
  2. INSERT 0 1
  3. Time: 0.781 ms

151-160

1. 在 T1 2 中执行以下语句,提交事务

  1. db2022=# commit;
  2. COMMIT
  3. Time: 108.364 ms
  4. db2022=# select * from test;
  5. id | value
  6. ----+-------
  7. 1 | 10
  8. 2 | 20
  9. 3 | 30
  10. 4 | 42
  11. (4 rows)
  12. 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

  1. db2022=# drop table if exists test;
  2. DROP TABLE
  3. Time: 146.183 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 186.755 ms

2. 在 T1 中执行以下语句,查询当前事务ID,然后插入数据

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.487 ms
  4. db2022=# select txid_current();
  5. txid_current
  6. --------------
  7. 14727
  8. (1 row)
  9. Time: 119.613 ms
  10. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  11. INSERT 0 2
  12. Time: 1.225 ms
  13. db2022=# insert into test (id, value) values (3, 30), (4, 40);
  14. INSERT 0 2
  15. Time: 0.565 ms

3. 在 T1 中执行以下语句,查询表test中的记录(包含隐藏字段)

  1. db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
  2. xmin | xmax | ctid | cmin | cmax | id | value
  3. -------+------+-------+------+------+----+-------
  4. 14727 | 0 | (0,1) | 0 | 0 | 1 | 10
  5. 14727 | 0 | (0,2) | 0 | 0 | 2 | 20
  6. 14727 | 0 | (0,3) | 1 | 1 | 3 | 30
  7. 14727 | 0 | (0,4) | 1 | 1 | 4 | 40
  8. (4 rows)
  9. Time: 0.924 ms

4. 在 T1 中执行以下语句,更新数据后查询表test中的记录(包含隐藏字段)

  1. db2022=# update test set value = 11 where id = 1;
  2. UPDATE 1
  3. Time: 0.719 ms
  4. db2022=# delete from test where id = 4;
  5. DELETE 1
  6. Time: 0.468 ms
  7. db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
  8. xmin | xmax | ctid | cmin | cmax | id | value
  9. -------+------+-------+------+------+----+-------
  10. 14727 | 0 | (0,2) | 0 | 0 | 2 | 20
  11. 14727 | 0 | (0,3) | 1 | 1 | 3 | 30
  12. 14727 | 0 | (0,5) | 2 | 2 | 1 | 11
  13. (3 rows)
  14. Time: 0.879 ms
  15. db2022=# commit;
  16. COMMIT
  17. Time: 27.930 ms

ctid 为插入这条记录的 cid。

5. 在 T1 中执行以下语句,更新数据后查询表test中的记录(包含隐藏字段)

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.308 ms
  4. db2022=# select txid_current();
  5. txid_current
  6. --------------
  7. 14728
  8. (1 row)
  9. Time: 0.444 ms
  10. db2022=# update test set value = 21 where id = 2;
  11. UPDATE 1
  12. Time: 0.578 ms
  13. db2022=# delete from test where id = 3;
  14. DELETE 1
  15. Time: 0.497 ms
  16. db2022=# update test set value = 22 where id = 2;
  17. UPDATE 1
  18. Time: 0.543 ms
  19. db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
  20. xmin | xmax | ctid | cmin | cmax | id | value
  21. -------+------+-------+------+------+----+-------
  22. 14727 | 0 | (0,5) | 2 | 2 | 1 | 11
  23. 14728 | 0 | (0,7) | 2 | 2 | 2 | 22
  24. (2 rows)
  25. Time: 0.649 ms
  26. db2022=# abort;
  27. ROLLBACK
  28. Time: 0.424 ms
  29. db2022=# select xmin, xmax, ctid, cmin, cmax, * from test;
  30. xmin | xmax | ctid | cmin | cmax | id | value
  31. -------+-------+-------+------+------+----+-------
  32. 14727 | 14728 | (0,2) | 0 | 0 | 2 | 20
  33. 14727 | 14728 | (0,3) | 1 | 1 | 3 | 30
  34. 14727 | 0 | (0,5) | 2 | 2 | 1 | 11
  35. (3 rows)
  36. Time: 0.678 ms

即使abort,xmax还是相应更新了?

查看事务的快照

1. 在 T1 中执行以下语句,创建数据表test并插入数据

  1. db2022=# drop table if exists test;
  2. DROP TABLE
  3. Time: 151.743 ms
  4. db2022=# create table test (id int primary key, value int);
  5. NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for table "test"
  6. CREATE TABLE
  7. Time: 240.563 ms
  8. db2022=# insert into test (id, value) values (1, 10), (2, 20);
  9. INSERT 0 2
  10. Time: 131.728 ms

2. 在 T1 中执行以下语句,设置事务隔离级别,查询事务ID和快照

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.344 ms
  4. db2022=# set transaction isolation level read committed;
  5. SET
  6. Time: 0.302 ms
  7. db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
  8. txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
  9. --------------+-----------------------+-------+------+-------+------+------+----+-------
  10. 14734 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
  11. 14734 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
  12. (2 rows)
  13. Time: 0.966 ms

在 T2 中执行以下语句,设置事务隔离级别,查询事务ID和快照

  1. db2022=# begin;
  2. BEGIN
  3. Time: 0.318 ms
  4. db2022=# set transaction isolation level read committed;
  5. SET
  6. Time: 0.289 ms
  7. db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
  8. txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
  9. --------------+-----------------------+-------+------+-------+------+------+----+-------
  10. 14735 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
  11. 14735 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
  12. (2 rows)
  13. Time: 0.997 ms

3. 在 T3 中执行以下语句,设置事务隔离级别,查询事务ID和快照

  1. db2022=# begin;
  2. BEGIN
  3. db2022=# set transaction isolation level repeatable read;
  4. SET
  5. db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
  6. txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
  7. --------------+-----------------------+-------+------+-------+------+------+----+-------
  8. 14736 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
  9. 14736 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
  10. (2 rows)

4. 在 T1 中提交事务

5. 在 T2 中执行以下语句,查询事务ID和快照

  1. db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
  2. txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
  3. --------------+-----------------------+-------+------+-------+------+------+----+-------
  4. 14735 | 14735:14735: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
  5. 14735 | 14735:14735: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
  6. (2 rows)
  7. Time: 0.877 ms

6. 在 T3 中执行以下语句,查询事务ID和快照

  1. db2022=# select txid_current(),txid_current_snapshot(), xmin, xmax, ctid, cmin, cmax, * from test;
  2. txid_current | txid_current_snapshot | xmin | xmax | ctid | cmin | cmax | id | value
  3. --------------+-----------------------+-------+------+-------+------+------+----+-------
  4. 14736 | 14734:14734: | 14733 | 0 | (0,1) | 0 | 0 | 1 | 10
  5. 14736 | 14734:14734: | 14733 | 0 | (0,2) | 0 | 0 | 2 | 20
  6. (2 rows)

说明:提交读每条语句都获取快照,可重复读只在获得txid时生成快照

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注