SQL,如何测试并发事务

时间:2016-01-26 02:09:36

标签: mysql sql sql-server postgresql transactions

假设存在一个包含something列的表id, foo, bar, baz, qux, norf, updated_at,并且有人希望测试在此表上工作的并发事务时可能发生的各种用例,例如:

用例:如果您检查以下交易 T1 T2 ,例如如何测试从哪个事务隔离级别插入 T2 将在 T1中的第一个和第二个SELECT之间进行COMMIT

,那么> T2 将在第二个SELECT中可用

所以我在这里测试phantom read的一些变体我猜,虽然SELECT语句不同

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

(顺便说一下,使用一个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;

请不要发布答案,例如“READ COMMITTED是postgre的默认事务级别,你不需要指定它”我只是作为一个例子使用它,或者“你将通过使用REPEATABLE READ来解决问题postgre“因为我想从测试中得到答案。

虽然我在少数几个地方提到了postgre,我正在使用mysqlsql-server,因为问题与它们都没有关系。

我也检查过已提出的问题:
How to test MySQL transactions?
How to test concurrency locally?

1 个答案:

答案 0 :(得分:3)

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

我确信你可以使用各自的工具与其他数据库做一些非常相似的事情。

示例:

窗口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;

窗口2

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

窗口1

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

COMMIT;