SQL,如何测试并发事务

SQL, how to test concurrent transactions

假设有一个 table somethingid, foo, bar, baz, qux, norf, updated_at 并且想要测试在处理某些事情的并发事务时可能发生的各种用例这个table,例如:

用例: 如果您检查以下事务 T1T2,例如如何测试从 T2 插入的事务隔离级别将在第二个 SELECT 可用,假设 T2 将在第一个和第二个之间提交SELECT 在 T1?

所以我想在这里测试 phantom read 的一些变体,尽管 SELECT 语句不同 ?

我唯一的想法是在两个 SELECT 语句之间使用 SELECT PG_SLEEP(N); 并打开两个数据库连接(例如某些数据库客户端的 2 个实例,例如 PgAdmin)一个来处理 T1 和一个处理 T2 而不是手动启动 T1 让第一个 SELECT 完成 PG_SLEEP(10) 将触发,而不是手动启动 T2 并希望看到 T1 的结果集并手动比较它。但似乎这是不可能的,因为我没有找到任何数据库客户端可以 return 来自 2+ SELECT 语句的多个结果集。

(顺便说一句,使用一个 SELECT 而不是两个会很棒,以某种方式合并为一个 SELECT 但我不知道该怎么做)

T1:

START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
...
SELECT sum(foo) as foo
FROM something
WHERE bar = 1 AND updated_at <= '...' AND norf = 2
UNION ALL
SELECT sum(foo)
FROM something
WHERE bar = 1 AND baz IN (1, 9, 10) AND updated_at > '...'
GROUP BY bar;

SELECT PG_SLEEP(10);

SELECT bar, qux, sum(foo) AS foo
FROM something
WHERE norf = 2
GROUP BY bar, qux;

COMMIT;

T2:

START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
...
INSERT INTO something VALUES(...);
...
COMMIT;

请不要post回答"READ COMMITTED is default transaction level in postgre you don't need to specify it"我只是用它作为例子,或者"you will solve problem by using REPEATABLE READ in postgre"因为我想从测试中得到那个答案。

虽然我在少数地方提到了 postgre,但我使用的是 mysqlsql-server,因为问题与它们都无关。

我还检查了已经提出的问题:
How to test MySQL transactions?
How to test concurrency locally?

对于 Sql 服务器,我通过在 Sql Server Management Studio 中打开两个不同的 windows 来测试此类场景。每个 window 都有自己的数据库连接。然后,我逐步执行 T1 和 T2 的相关部分,以重现所需的测试用例。

我相信您可以使用其他数据库使用它们各自的工具来做一些非常相似的事情。

示例:

Window 1

START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
...
SELECT sum(foo) as foo
FROM something
WHERE bar = 1 AND updated_at <= '...' AND norf = 2
UNION ALL
SELECT sum(foo)
FROM something
WHERE bar = 1 AND baz IN (1, 9, 10) AND updated_at > '...'
GROUP BY bar;

Window 2

START TRANSACTION;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
...
INSERT INTO something VALUES(...);
...
COMMIT;

Window 1

SELECT bar, qux, sum(foo) AS foo
FROM something
WHERE norf = 2
GROUP BY bar, qux;

COMMIT;