次のようなPostgreSQL関数は自動的にトランザクション対応ですか?
CREATE OR REPLACE FUNCTION refresh_materialized_view(name)
RETURNS integer AS
$BODY$
DECLARE
_table_name ALIAS FOR $1;
_entry materialized_views%ROWTYPE;
_result INT;
BEGIN
EXECUTE 'TRUNCATE TABLE ' || _table_name;
UPDATE materialized_views
SET last_refresh = CURRENT_TIMESTAMP
WHERE table_name = _table_name;
RETURN 1;
END
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
つまり、関数の実行中にエラーが発生した場合、変更はロールバック?これがデフォルトの動作ではない場合、関数transactionalを作成するにはどうすればよいですか?
PostgreSQL 12 update: トランザクション制御が可能なトップレベルのPROCEDURE
sのサポートは制限されています 。通常のSQL呼び出し可能関数でトランザクションを管理することはまだできないので、新しいトップレベルプロシージャを使用する場合を除いて、以下は真のままです。
関数は、呼び出し元のトランザクションの一部です。トランザクションがロールバックされると、それらの効果はロールバックされます。トランザクションがコミットされると、彼らの作業はコミットされます。関数内のBEGIN ... EXCEPT
ブロックは、SAVEPOINT
およびROLLBACK TO SAVEPOINT
SQLステートメントのようなセーブポイントのように(そして内部で使用するために)動作します。
関数は、BEGIN ... EXCEPT
エラー処理を除いて、完全に成功するか完全に失敗します。関数内でエラーが発生し、処理されない場合、関数を呼び出しているトランザクションは中止されます。中止されたトランザクションはコミットできません。コミットしようとすると、COMMIT
はROLLBACK
として扱われ、エラーの他のトランザクションと同じです。観察する:
regress=# BEGIN;
BEGIN
regress=# SELECT 1/0;
ERROR: division by zero
regress=# COMMIT;
ROLLBACK
ゼロ除算によりエラー状態にあるトランザクションがCOMMIT
?でどのようにロールバックするかを確認してください。
明示的なサラウンドトランザクションなしで関数を呼び出す場合、ルールは他のPgステートメントとまったく同じです。
BEGIN;
SELECT refresh_materialized_view(name);
COMMIT;
(COMMIT
でエラーが発生した場合、SELECT
は失敗します)。
PostgreSQLは(まだ)関数の自律型トランザクションをサポートしていません。この場合、プロシージャ/関数は呼び出し側トランザクションとは無関係にコミット/ロールバックできます。これは、 dblink を介して新しいセッションを使用してシミュレートできます。
[〜#〜] but [〜#〜]、PostgreSQLにはトランザクションではない、または不完全なトランザクションが存在します。通常のBEGIN; do stuff; COMMIT;
ブロックで非トランザクション動作を行う場合、関数でも非トランザクション動作を行います。たとえば、nextval
およびsetval
、TRUNCATE
など。
私のPostgreSQLの知識はCraig Ringerの知識よりも浅いので、もっと短い答えをしようとします:はい。
エラーのある関数を実行した場合、データベースに影響を与えるステップはありません。
また、PgAdmin
でクエリを実行すると、同じことが起こります。
たとえば、クエリで実行する場合:
_update your_table yt set column1 = 10 where yt.id=20;
select anything_that_do_not_exists;
_
行の更新、_id = 20
_の_your_table
_はデータベースに保存されません。
2018年9月更新
概念を明確にするために、非トランザクション関数nextvalを使用した小さな例を作成しました。
まず、シーケンスを作成しましょう。
_create sequence test_sequence start 100;
_
次に、実行してみましょう。
update your_table yt set column1 = 10 where yt.id=20; select nextval('test_sequence'); select anything_that_do_not_exists;
さて、別のクエリを開いて実行すると
select nextval('test_sequence');
更新がコミットされなかったにもかかわらず、最初の値(100)が後者のクエリで使用されたため(つまり、シーケンスがトランザクションではないため)101になります。
機能レベルでは、国境を越えていません。つまり、関数内の各ステートメントは、デフォルトのdb自動コミット値である単一のトランザクションに属します。自動コミットはデフォルトでtrueです。しかし、とにかく、を使用して関数を呼び出す必要があります
select schemaName.functionName()
上記のステートメント 'select schemaName.functionName()'は単一のトランザクションです。トランザクションT1に名前を付けましょう。したがって、関数内のすべてのステートメントはトランザクションT1に属します。このように、関数は単一のトランザクション内にあります。
https://www.postgresql.org/docs/current/static/plpgsql-structure.html
PL/pgSQLのステートメントをグループ化するためのBEGIN/ENDの使用と、トランザクション制御のための同様の名前のSQLコマンドを混同しないことが重要です。 PL/pgSQLのBEGIN/ENDはグループ化専用です。トランザクションを開始または終了しません。関数とトリガープロシージャは、外部クエリによって確立されたトランザクション内で常に実行されます。実行するコンテキストがないため、トランザクションを開始またはコミットできません。ただし、EXCEPTION句を含むブロックは、サブトランザクションを効果的に形成します。外部トランザクションに影響を与えることなくロールバックされます。詳細については、セクション39.6.6を参照してください。