简体   繁体   English

PostgreSQL永远挂在可序列化事务上

[英]postgresql hang forever on serializable transaction

I use libpqxx for my connection to postgresql. 我使用libpqxx连接到PostgreSQL。 And everything was ok, until i run serialazable query on one table on one row. 一切正常,直到我在一行的一张表上运行serialazable查询。

table: 表:

CREATE TABLE t1(id integer primary key);

postgres 9.4.4_x64 的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();

my program hang forever. 我的程序永远挂起。 hang in PQexec function. 挂在PQexec函数中。 Why? 为什么? Is i think it must rollback one of transaction? 我是否认为必须回滚交易之一? but no? 但不是? just hang. 挂了

UPDATE: same result for pure libpq: 更新:纯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 - same hang PostgreSQL 9.1-相同的挂起

The hang has nothing to do with the serializable isolation level. 挂起与可serializable隔离级别无关。

I'm no libpqxx expert, but your example appears to be running both transactions in a single thread. 我不是libpqxx专家,但是您的示例似乎在单个线程中运行了两个事务。 That's your problem. 那是你的问题。

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

The above statement has to wait for t1 to commit or rollback before completing, but t1.commit() never gets a chance to execute. 上面的语句必须等待t1提交或回滚才能完成,但是t1.commit()永远没有机会执行。 Deadlock! 僵局! This is absolutely normal, and will happen regardless of your chosen isolation level. 这绝对是正常的,并且无论您选择的隔离级别如何,都会发生这种情况。 This is just a consequence of trying to run statements from 2 concurrent transactions in the same thread of execution, not a good idea. 这只是试图在同一执行线程中从2个并发事务中运行语句的结果,不是一个好主意。

Try running both transactions on different threads, and your hang will go away. 尝试在不同的线程上运行两个事务,您的挂起将消失。

If only the two transaction are involved, you should get a unique violation error for transaction t2 - exactly the same as with default READ COMMITTED isolation level: 如果仅涉及两个事务,则应该获得事务t2的唯一违规错误-与默认的READ COMMITTED隔离级别完全相同

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

t1 tried the insert first and wins regardless which transaction tries to commit first. t1首先尝试插入,然后不管哪个事务首先尝试提交均获胜。 All following transactions trying to insert the same key wait for the first. 接下来的所有尝试插入相同密钥的事务都将等待第一个事务。 Again, this is valid for READ COMMITTED and SERIALIZABLE alike. 同样,这对于READ COMMITTEDSERIALIZABLE都是有效的。

A possible explanation would be that a third transaction is involved, which tried to insert the same key first and is still open. 可能的解释是,涉及到第三笔交易该笔交易试图首先插入相同的密钥,但仍处于打开状态。 Or several such transactions, artefacts of your tests. 或几次这样的交易,即测试的人工制品。

All transactions wait for the first one that tried to insert the same key. 所有事务都等待一个尝试插入相同密钥的事务。 If that one commits, all other get a unique violation. 如果提交,则其他所有都将发生唯一违规。 If it rolls back, the next in line gets its chance. 如果它回滚,那么下一行将获得机会。

To check look at pg_stat_activity (being connected to the same database): 要检查一下pg_stat_activity (已连接到同一数据库):

SELECT * FROM pg_stat_activity;

More specifically: 进一步来说:

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

Then commit / rollback the idle transaction. 然后提交/回滚空闲事务。 Or brute-force: terminate that connection. 还是蛮力的:终止该连接。 Details: 细节:

form postgres team: 组建Postgres小组:

"In concurrent programming, a deadlock is a situation in which two or more competing actions are each waiting for the other to finish, and thus neither ever does." “在并发编程中,死锁是这样一种情况,其中两个或更多竞争的动作各自在等待对方完成,因此永远不会。” https://en.wikipedia.org/wiki/Deadlock https://en.wikipedia.org/wiki/Deadlock

definition it is not a deadlock in the first place. 定义首先不是死锁。 "c1" is not waiting for "c2" to finish and can happily go about its business with id=104. “ c1”不等待“ c2”完成,可以愉快地进行id = 104的业务。 However, your application never gives c1 the next command because it is stubbornly waiting for "c2" to perform its insert - which it cannot due to the lock held by "c1". 但是,您的应用程序永远不会给c1下一条命令,因为它顽固地等待“ c2”执行其插入-由于“ c1”持有的锁,它无法执行该操作。

Lock testing can be done within a single thread but deadlock testing implies that both connections need to simultaneously be attempting to execute a command - which a single program cannot accomplish without threading. 锁测试可以在单个线程中完成,但是死锁测试意味着两个连接都需要同时尝试执行命令-如果没有线程,单个程序就无法完成。

David J. 戴维·J。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM