PostgreSQL information_schema.tables 和 TRANSACTION ISOLATION LEVEL

Tre*_*reg 5 java postgresql transactions race-condition

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

我不明白的一件事是为什么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

    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

我得到的例外是:

org.postgresql.util.PSQLException: ERROR: relation "myschema.config" does not exist
Run Code Online (Sandbox Code Playgroud)

这怎么可能?我认为ISOLATION LEVEL SERIALIZABLE会保护我免受这种情况的影响。那是因为删除模式是太具体的操作而无法保持隔离吗?还是我在做一些根本错误的事情?

Mik*_*ll' 2

SQL 语句set transaction isolation level . . .不会启动事务。(无论如何,这不是您感兴趣的意义上的。)

按照您的代码,您可以像这样编写 SQL 语句

set transaction isolation level serializable;
begin transaction;
...
Run Code Online (Sandbox Code Playgroud)

或者像这样。

begin transaction isolation level serializable;
...
Run Code Online (Sandbox Code Playgroud)

相关 PostgreSQL 文档

但您不需要为此进行可序列化的事务。您可以通过在两个终端会话中运行 psql 来进行测试。

sandbox=# 开始交易;
开始
                                          sandbox=# 开始交易;
                                          开始

sandbox=# select * from foo 进行更新;
 foo_id
--------
      1
(1 行)
                                          sandbox=# 删除表 foo;
                                          [等待。。.]
sandbox=# 更新 foo set foo_id = 2;
更新1
沙箱=#从foo中选择*;
 foo_id
--------
      2
(1 行)

沙箱=#提交;
犯罪
                                          掉落表
                                          沙箱=#提交;
                                          犯罪

沙箱=#从foo中选择*;
错误:关系“foo”不存在
第 1 行:从 foo 中选择 *;

话虽如此,设计一个可以定期删除和(我认为)创建表和模式的数据库似乎是一个坏主意。