6

INSERTAFTERまたはUPDATEAFTERトリガー内のロールバックは、トランザクション全体またはトリガーの理由である現在の行のみをロールバックしますか?それはCommitと同じですか?

トランザクションにMSTDCを使用する現在のプロジェクトコードで確認しようとしましたが、トランザクション全体が中止されたように見えます。

トリガーのロールバックがトランザクション全体をロールバックする場合、現在の行のみを制限するための回避策はありますか。

これでsybaseへのリンクが見つかりましたが、SQLサーバーには何もありません

4

3 に答える 3

9

はい、トランザクション全体をロールバックします。

それはすべてドキュメントにあります(備考を参照)。私が強調したコメントに注意してください-それは私が言う非常に重要です!!

ROLLBACK TRANSACTION がトリガーで発行された場合:

現在のトランザクションのその時点までに行われたすべてのデータ変更は、トリガーによって行われたものも含めてロールバックされます。

トリガーは、ROLLBACK ステートメントの後に残りのステートメントを実行し続けます。これらのステートメントのいずれかがデータを変更する場合、変更はロールバックされません。これらの残りのステートメントの実行によって、ネストされたトリガーが起動されることはありません。

トリガーを起動したステートメントの後のバッチ内のステートメントは実行されません。

于 2012-07-13T11:31:39.463 に答える
1

既にお知らせしたように、トリガーによって発行されたステートメントのみをロールバックするように ROLLBACK コマンドを変更/調整することはできません。

トリガーによってのみ実行されるアクションを「ロールバック」する方法が必要な場合は、回避策として、アクションを実行する前にトリガーがそれらのアクションによって例外的な状況が発生しないことを確認するようにトリガーを変更することを検討できます。トランザクション全体がロールバックします。

たとえば、トリガーが行を挿入する場合、次のようなチェックを追加して、新しい行が一意の制約 (または外部キー制約) に違反していないことを確認します。

IF NOT EXISTS (
  SELECT *
  FROM TableA
  WHERE …  /* a condition to test if a row or rows you are about
              to insert aren't going to violate any constraint */
)
BEGIN
  INSERT INTO TableA …
END;

または、トリガーが行を削除する場合は、他のテーブルによって参照されている行を削除しようとしていないかどうかを確認します (その場合、通常、どのテーブル行を参照している可能性があるかを事前に知る必要があります)。

IF NOT EXISTS (
  SELECT * FROM TableB WHERE …
)
AND NOT EXISTS (
  SELECT * FROM TableC WHERE …
)
AND …
BEGIN
  DELETE FROM TableA WHERE …
END

同様に、更新ステートメントがある場合は、そのチェックを行う必要があります。

于 2012-07-16T05:38:53.293 に答える
0

いくつかのセーブポイントを指定しない限り、ロールバック コマンドは @@trancount が 0 になるまですべてをロールバックします。

最善の方法は、もう一度コードを調べてビジネス要件を確認し、トリガーでロールバックが必要な理由を確認することです。

于 2012-07-13T13:37:10.030 に答える