【问题标题】:PostgreSQL information_schema.tables and TRANSACTION ISOLATION LEVELPostgreSQL information_schema.tables 和 TRANSACTION ISOLATION LEVEL
【发布时间】:2015-03-02 23:42:39
【问题描述】:

在 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

    /* ... */
}

我得到的例外是:

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

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

【问题讨论】:

  • 并非所有数据库都将 DDL 视为“在”事务中。 (我不确定pg的立场是什么。)

标签: java postgresql transactions race-condition


【解决方案1】:

SQL 语句set transaction isolation level . . . 不启动事务。 (反正不是你感兴趣的意思。)

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

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

或者像这样。

begin transaction isolation level serializable;
...

Relevant PostgreSQL docs

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

sandbox=# 开始交易; 开始 sandbox=# 开始交易; 开始 sandbox=# select * from foo 进行更新; foo_id -------- 1 (1 行) sandbox=# 删除表 foo; [等待。 . .] sandbox=# 更新 foo 设置 foo_id = 2; 更新 1 sandbox=# select * from foo; foo_id -------- 2 (1 行) 沙箱=#提交; 犯罪 删除表 沙箱=#提交; 犯罪 sandbox=# select * from foo; 错误:关系“foo”不存在 第 1 行:从 foo 中选择 *;

说了这么多,设计一个可能定期删除表和模式并(我认为)创建的数据库似乎是个坏主意。

【讨论】:

  • 我看到运行两个冲突的事务会导致需要冻结其中一个以避免成本不高。现在我还看到了 psql 事务的工作原理——它们相互阻止而不是发生冲突。是这样吗对?我做了类似的实验,插入违反约束的重复项,似乎是的。
  • 基本正确。每个事务都可以设置自己的isolation level。每个事务的隔离级别告诉 PostgreSQL 它可以容忍其他并发事务的影响。在英语中,waiting 可能比 freezing 更好;在英语中,freezing 建议 deadlock,但 waiting 不建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多