作为一个具体的组成例子,我想这样做:
CREATE FUNCTION add_new_row(rowtext TEXT) RETURNS VOID AS $$ BEGIN INSERT INTO data_table VALUES (rowtext); UPDATE row_counts_table SET count=count+1; END; $$ LANGUAGE plpgsql SECURITY DEFINER;
并想象我想确保这个函数总是作为可序列化的事务执行(是的,是的,Postgresql SERIALIZABLE是不正确的可序列化,但这不是重点)。我不想要它被称为
START TRANSACTION ISOLATION LEVEL SERIALIZABLE; SELECT add_new_row('foo'); COMMIT;
那么如何将所需的隔离级别推到功能中呢?我相信我不能把隔离级别放在BEGIN语句中,如the manual says
It is important not to confuse the use
of BEGIN/END for grouping statements
in PL/pgsql with the similarly-named
sql commands for transaction control.
PL/pgsql’s BEGIN/END are only for
grouping; they do not start or end a
transaction. Functions and trigger
procedures are always executed within
a transaction established by an outer
query — they cannot start or commit
that transaction,since there would be
no context for them to execute in.
对我来说最明显的做法是在函数定义中的某个地方使用SET TRANSACTION,例如:
CREATE FUNCTION add_new_row(rowtext TEXT) RETURNS VOID AS $$ BEGIN SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; INSERT INTO data_table VALUES (rowtext); UPDATE row_counts_table SET count=count+1; END; $$ LANGUAGE plpgsql SECURITY DEFINER;
虽然这将被接受,但我不清楚,我可以依靠这个工作。 SET TRANSACTION的documentation说
If SET TRANSACTION is executed without
a prior START TRANSACTION or BEGIN,it
will appear to have no effect,since
the transaction will immediately end.
这让我感到困惑,因为如果我调用一个孤立的SELECT add_new_row(‘foo’);语句我希望(假设我没有禁用自动提交)SELECT作为具有会话默认隔离级别的单行事务运行。
manual还说:
The transaction isolation level cannot
be changed after the first query or
data-modification statement (SELECT,
INSERT,DELETE,UPDATE,FETCH,or
COPY) of a transaction has been
executed.
那么如果从具有较低隔离级别的事务中调用该函数会发生什么,例如:
START TRANSACTION ISOLATION LEVEL READ COMMITTED; UPDATE row_counts_table SET count=0; SELECT add_new_row('foo'); COMMIT;
对于一个奖金问题:该功能的语言有什么区别吗?将PL / pgsql中的隔离级别设置为与纯sql不同?
我是标准和记录的最佳实践的粉丝,所以任何体面的参考将不胜感激。
你可以做的是让你的功能检查当前的事务隔离级别是什么,如果不是你想要的事情,中止它。您可以通过运行SELECT current_setting(‘transaction_isolation’)然后检查结果来执行此操作。