1

我使用 libpqxx 连接到 postgresql。一切都很好,直到我在一行的一张表上运行可序列化查询。

桌子:

CREATE TABLE t1(id integer primary key);

postgres 9.4.4_x64

pqxx::connection c1(conn_str);
pqxx::connection c2(conn_str);

pqxx::transaction<pqxx::isolation_level::serializable> t1(c1);
t1.exec("INSERT INTO t1 (id) VALUES (25)");

pqxx::transaction<pqxx::isolation_level::serializable> t2(c2);
t2.exec("INSERT INTO t1 (id) VALUES (25)"); //hang here

t2.commit();
t1.commit();

我的程序永远挂起。挂在 PQexec 函数中。为什么?我认为它必须回滚其中一项交易吗?但不是?挂了。

更新:纯 libpq 的结果相同:

c1 = PQconnectdb(conninfo);
c2 = PQconnectdb(conninfo);

res1 = PQexec(c1, "BEGIN");
PQclear(res1);


res1 = PQexec(c1, "INSERT INTO t1 (id) VALUES (104)");
PQclear(res1);

res2 = PQexec(c2, "BEGIN");
PQclear(res2);

res2 = PQexec(c2, "INSERT INTO t1 (id) VALUES (104)");
PQclear(res2);

res2 = PQexec(c2, "END");
PQclear(res2);

res1 = PQexec(c1, "END");
PQclear(res1);

postgresql 9.1 - 同样挂起

4

3 回答 3

4

serializable挂起与隔离级别无关。

我不是libpqxx专家,但您的示例似乎是在一个线程中运行两个事务。那是你的问题。

t2.exec("INSERT INTO t1 (id) VALUES (25)");

上述语句必须等待t1提交或回滚才能完成,但t1.commit()永远没有机会执行。僵局!这是绝对正常的,无论您选择何种隔离级别都会发生。这只是尝试在同一个执行线程中运行来自 2 个并发事务的语句的结果,这不是一个好主意。

尝试在不同的线程上运行这两个事务,你的挂起就会消失。

于 2015-08-28T03:09:19.217 回答
0

组建 postgres 团队:

“在并发编程中,死锁是两个或多个相互竞争的动作都在等待对方完成的情况,因此两者都不会。” https://en.wikipedia.org/wiki/Deadlock

定义它首先不是死锁。“c1”不等待“c2”完成,可以愉快地使用 id=104 开展业务。但是,您的应用程序永远不会给 c1 下一个命令,因为它顽固地等待“c2”执行其插入 - 由于“c1”持有的锁,它不能执行插入。

锁测试可以在单个线程中完成,但死锁测试意味着两个连接需要同时尝试执行命令——如果没有线程,单个程序无法完成。

大卫·J。

于 2015-08-31T14:03:15.423 回答
0

如果只涉及两个事务,您应该得到事务t2的唯一违规错误-与默认隔离级别完全相同:READ COMMITTED

ERROR:  duplicate key value violates unique constraint "t1_pkey"
DETAIL:  Key (id)=(25) already exists.

t1首先尝试插入,并且无论哪个事务首先尝试提交都获胜。尝试插入相同密钥的所有后续事务都将等待第一个。同样,这对READ COMMITTEDSERIALIZABLE类似的都是有效的。

一个可能的解释是涉及第三个事务,它试图首先插入相同的密钥并且仍然是打开的。或者几个这样的交易,你的测试的人工制品。

所有事务都等待一个尝试插入相同密钥的事务。如果那个人犯了,所有其他人都会得到一个独特的违规行为。如果它回滚,下一个排队的人就有机会。

要查看pg_stat_activity(连接到同一个数据库):

SELECT * FROM pg_stat_activity;

进一步来说:

SELECT * FROM pg_stat_activity WHERE state = 'idle in transaction';

然后提交/回滚空闲事务。或蛮力:终止该连接。细节:

于 2015-08-27T18:33:30.170 回答