设置postgresql存储过程的隔离级别

希望是一个简单的问题,但是我并不容易找到一个体面的答案。我可靠地通知PostgreSQL(特别是版本9.0.4)中的存储过程(用户定义的DB函数)本质上是事务性的,因为它们通过本身是一个事务的SELECT语句来调用。那么如何选择存储过程的隔离级别?我相信其他DBMS,所需的事务块将被封装在START TRANSACTION块中,所需的隔离级别是可选参数。

作为一个具体的组成例子,我想这样做:

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’)然后检查结果来执行此操作。

http://stackoverflow.com/questions/6274457/set-isolation-level-for-postgresql-stored-procedures

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:设置postgresql存储过程的隔离级别