単純な質問であることを願っていますが、まともな答えをすぐに見つけられなかった質問です。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
にあるように、ステートメントに分離レベルを入れることはできないと思います
PL/pgSQL でステートメントをグループ化するための BEGIN/END の使用を、トランザクション制御のための同様の名前の SQL コマンドと混同しないことが重要です。PL/pgSQL の BEGIN/END はグループ化専用です。トランザクションを開始または終了しません。関数とトリガー プロシージャは常に、外部クエリによって確立されたトランザクション内で実行されます。実行するコンテキストがないため、そのトランザクションを開始またはコミットすることはできません。
私にとって最も明白なアプローチ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
言う
START TRANSACTION または BEGIN を事前に指定せずに SET TRANSACTION を実行すると、トランザクションがすぐに終了するため、効果がないように見えます。
単一のステートメントを呼び出すとSELECT add_new_row('foo');
(自動コミットを無効にしていない場合)、SELECT がセッションのデフォルトの分離レベルで単一行のトランザクションとして実行されることが予想されるため、これは私を困惑させます。
マニュアルには次のようにも書かれています。
トランザクションの最初のクエリまたはデータ変更ステートメント (SELECT、INSERT、DELETE、UPDATE、FETCH、または COPY) が実行された後は、トランザクション分離レベルを変更できません。
したがって、関数がより低い分離レベルのトランザクション内から呼び出された場合はどうなるでしょうか。たとえば、次のようになります。
START TRANSACTION ISOLATION LEVEL READ COMMITTED;
UPDATE row_counts_table SET count=0;
SELECT add_new_row('foo');
COMMIT;
おまけの質問: 関数の言語によって違いはありますか? PL/pgSQL では、プレーン SQL とは異なる分離レベルを設定しますか?
私は標準と文書化されたベスト プラクティスのファンです。