PostgreSQL information_schema.tables和TRANSACTION ISOLATION LEVEL

时间:2015-03-02 23:42:39

标签: java postgresql transactions race-condition

在PostgreSQL中,我面临竞争条件。我的表和模式可能会被系统中的单独进程删除。如果架构和表存在,则使用idiom ,然后读取内容因此一般不起作用,因为该表可能不再存在于语句的中间。

有一点我不明白为什么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 个答案:

答案 0 :(得分: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;

说了这么多,设计一个数据库,其中表格和模式可能定期被删除(我推测)创建似乎是一个坏主意。