![](/img/trans.png)
[英]Postgresql Serializable Transaction not working as expected
[英]postgresql hang forever on serializable transaction
我使用libpqxx連接到PostgreSQL。 一切正常,直到我在一行的一張表上運行serialazable查詢。
表:
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-相同的掛起
掛起與可serializable
隔離級別無關。
我不是libpqxx
專家,但是您的示例似乎在單個線程中運行了兩個事務。 那是你的問題。
t2.exec("INSERT INTO t1 (id) VALUES (25)");
上面的語句必須等待t1
提交或回滾才能完成,但是t1.commit()
永遠沒有機會執行。 僵局! 這絕對是正常的,並且無論您選擇的隔離級別如何,都會發生這種情況。 這只是試圖在同一執行線程中從2個並發事務中運行語句的結果,不是一個好主意。
嘗試在不同的線程上運行兩個事務,您的掛起將消失。
如果僅涉及兩個事務,則應該獲得事務t2的唯一違規錯誤-與默認的READ COMMITTED
隔離級別完全相同 :
ERROR: duplicate key value violates unique constraint "t1_pkey" DETAIL: Key (id)=(25) already exists.
t1首先嘗試插入,然后不管哪個事務首先嘗試提交均獲勝。 接下來的所有嘗試插入相同密鑰的事務都將等待第一個事務。 同樣,這對於READ COMMITTED
和SERIALIZABLE
都是有效的。
可能的解釋是,涉及到第三筆交易 , 該筆交易試圖首先插入相同的密鑰,但仍處於打開狀態。 或幾次這樣的交易,即測試的人工制品。
所有事務都等待第一個嘗試插入相同密鑰的事務。 如果提交,則其他所有都將發生唯一違規。 如果它回滾,那么下一行將獲得機會。
要檢查一下pg_stat_activity
(已連接到同一數據庫):
SELECT * FROM pg_stat_activity;
進一步來說:
SELECT * FROM pg_stat_activity WHERE state = 'idle in transaction';
然后提交/回滾空閑事務。 還是蠻力的:終止該連接。 細節:
組建Postgres小組:
“在並發編程中,死鎖是這樣一種情況,其中兩個或更多競爭的動作各自在等待對方完成,因此永遠不會。” https://en.wikipedia.org/wiki/Deadlock
定義首先不是死鎖。 “ c1”不等待“ c2”完成,可以愉快地進行id = 104的業務。 但是,您的應用程序永遠不會給c1下一條命令,因為它頑固地等待“ c2”執行其插入-由於“ c1”持有的鎖,它無法執行該操作。
鎖測試可以在單個線程中完成,但是死鎖測試意味着兩個連接都需要同時嘗試執行命令-如果沒有線程,單個程序就無法完成。
戴維·J。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.