2015-03-02 64 views
4

在PostgreSQL中,我面臨競爭條件。系統中的單獨進程可能會刪除我的表和模式。如果模式和表存在,則使用成語,則讀取內容因此一般不起作用,因爲表可能在語句中間不存在。PostgreSQL information_schema.tables和TRANSACTION ISOLATION LEVEL

我不明白的一件事是爲什麼SET TRANSACTION ISOLATION LEVEL SERIALIZABLE沒有幫助。我想我可能期望在我的交易中對模式和表格有一致的看法,但我不這樣認爲。下面是我的Java代碼:

pgConnection = DriverManager.getConnection(/* ... */); 
pgConnection.setAutoCommit(false); 

PreparedStatement statement = pgConnection.prepareStatement(
           "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;"); 
statement.execute(); 

statement = pgConnection.prepareStatement(
       "SELECT ('myschema','config') IN " + 
       "(SELECT table_schema,table_name FROM information_schema.tables);"); 

ResultSet result = statement.executeQuery(); 
result.next(); 
if(result.getBoolean(1)) { 
    statement = pgConnection.prepareStatement("SELECT key,value FROM myschema.config;"); 

    result = statement.executeQuery(); // here I'm often getting an exception 

    /* ... */ 
} 

我得到的例外是:

org.postgresql.util.PSQLException: ERROR: relation "myschema.config" does not exist 

這怎麼可能?我認爲ISOLATION LEVEL SERIALIZABLE將保護我免受這種情況。那是因爲刪除模式過於具體操作以保持隔離?或者我在做一些根本性錯誤?

+1

並非所有的數據庫都認爲DDL是「在」一個事務中。 (我不確定pg的立場是什麼) – user2864740 2015-03-05 22:04:53

回答

2

SQL語句set transaction isolation level . . .未啓動事務。 (而不是在你感興趣的,反正感覺。)

按照你的代碼,你會寫SQL語句要麼喜歡這個

set transaction isolation level serializable; 
begin transaction; 
... 

或類似這樣的。

begin transaction isolation level serializable; 
... 

Relevant PostgreSQL docs

但你並不需要爲這個序列化交易。您可以通過在兩個終端會話中運行psql來進行測試。

 
sandbox=# begin transaction; 
BEGIN 
              sandbox=# begin transaction; 
              BEGIN 

sandbox=# select * from foo for update; 
foo_id 
-------- 
     1 
(1 row) 
              sandbox=# drop table foo; 
              [waits . . .] 
sandbox=# update foo set foo_id = 2; 
UPDATE 1 
sandbox=# select * from foo; 
foo_id 
-------- 
     2 
(1 row) 

sandbox=# commit; 
COMMIT 
              DROP TABLE 
              sandbox=# commit; 
              COMMIT 

sandbox=# select * from foo; 
ERROR: relation "foo" does not exist 
LINE 1: select * from foo; 

說了這麼多,設計在表和模式可能是定期被丟棄和創建(我相信)似乎是一個壞主意的數據庫。

+0

我發現運行兩個衝突的轉換會導致需要凍結其中的一個以避免incostistency ..現在我還會看到psql事務如何工作 - 它們彼此阻塞而不是碰撞..是這樣嗎?我做了類似的實驗,插入違反約束條件的複製品,似乎是肯定的。 – Tregoreg 2015-03-11 22:54:13

+0

大部分是正確的。每個事務可以設置自己的[隔離級別](http://www.postgresql.org/docs/9.4/static/transaction-iso.html)。每個事務的隔離級別告訴PostgreSQL它可以容忍來自其他併發事務的影響。在英語中,* waiting *可能比* freeze *更好;英文*凍結*表示[死鎖](http://en.wikipedia.org/wiki/Deadlock),但*等待*不會。 – 2015-03-12 11:06:05