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会保护我免受这种情况的影响。那是因为删除模式是太具体的操作而无法保持隔离吗?还是我在做一些根本错误的事情?
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)
但您不需要为此进行可序列化的事务。您可以通过在两个终端会话中运行 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 中选择 *;
话虽如此,设计一个可以定期删除和(我认为)创建表和模式的数据库似乎是一个坏主意。
| 归档时间: |
|
| 查看次数: |
504 次 |
| 最近记录: |