在PostgreSQL中,我面临竞争条件.我的表和模式可能会被系统中的单独进程删除.如果存在schema和table,则使用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可以保护我免受这种情况的影响.那是因为删除模式是太具体的操作来保持隔离吗?还是我做了一些根本错误的事情?
最佳答案 SQL语句设置事务隔离级别. . .不会开始交易. (无论如何,你并不感兴趣.)
在你的代码之后,你会像这样编写SQL语句
set transaction isolation level serializable;
begin transaction;
...
或者像这样.
begin transaction isolation level serializable;
...
但是,您不需要可序列化的事务.您可以通过在两个终端会话中运行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;
说了这么多,设计一个数据库,其中可以定期删除表和模式,并且(我推测)创建它似乎是一个坏主意.