web-dev-qa-db-ja.com

単一ステートメントに関するトランザクションは何をしますか?

トランザクションが更新のペアの調整にどのように役立つかを理解しています。私が理解していないのは、トランザクションで単一のステートメントをラップすることです。これは、今まで見たものの90%です。実際、実際のコードでは、一連の論理的に関連するトランザクションを見つけるのが一般的です。それぞれが独自のトランザクションにラップされていますが、全体がトランザクションにラップされていません。

MS-SQLでは、トランザクションで単一の選択、単一の更新、単一の挿入、または単一の削除をラップすることの利点はありますか?

これは迷信的なプログラミングだと思います。

63
MatthewMartin

何もしません。すべての個別のSQLステートメント(ログのない一括挿入やテーブルの切り捨てなどのまれな例外はあります)は、明示的にそうであってもなくても、自動的に「トランザクション内」です(数百万の行を挿入、更新、または削除した場合でも) 。

編集:以下の@Phillipのコメントに基づいて... SQL Serverの現在のバージョンでは、一括挿入と切り捨てテーブルでもトランザクションログにsomeデータを書き込みますが、他の操作ほどではありません。トランザクションの観点からの重要な違いは、これらの他のタイプの操作では、変更されているデータベーステーブルのデータが、ロールバックできる状態のログにないことです。

つまり、ステートメントがデータベース内のデータに加えた変更はトランザクションログに記録されるため、操作が失敗した場合は元に戻すことができます。

「Begin Transaction」、「Commit Transaction」、および「RollBack Transaction」コマンドが提供する唯一の機能は、2つ以上の個別のSQLステートメントを同じトランザクションに入れることを可能にすることです。

編集:(マークのコメントを強化するために...)はい、これは「迷信的な」プログラミングに起因する可能性があります。または、データベーストランザクションの性質の根本的な誤解を示している可能性があります。より慈善的な解釈は、それが不適切である一貫性の過剰適用の結果であり、次のようなエマソンの婉曲表現の別の例であるということです。

愚かな一貫性は小さな心のホブゴブリンであり、
小さな政治家や哲学者や神々に崇拝されている

59
Charles Bretana

チャールズブレタナが言ったように、「それは何もしません」-すでに行われていることに加えて何もしません。

リレーショナルデータベースの「ACID」要件について聞いたことがありますか?その「A」はアトミックを意味します。つまり、ステートメントが完全に機能するか機能しないかのどちらかであり、ステートメントの実行中にno他のクエリを実行できますそのクエリの影響を受けるデータ。BEGIN TRANSACTION/COMMITは、このロック機能を複数のステートメントによって実行される作業に「拡張」しますが、単一のステートメントには何も追加しません。

ただし、データベースのトランザクションログは常にデータベースが変更(挿入、更新、削除)されるときに書き込まれます。これは選択肢ではなく、人々を苛立たせる傾向があります。はい、一括挿入とリカバリモードには奇妙な点がありますが、それでも書き込みは行われます。

ここでも分離レベルに名前を付けます。これを混乱させると、個々のコマンドに影響しますが、そうすることによって、宣言されたトランザクションでラップされたクエリが「スタンドアロン」クエリと異なる動作をすることはありません。 (これらは非常に強力で、複数ステートメントで宣言されたトランザクションでは非常に危険な場合があります。)また、 "nolock"は挿入/更新にしないには適用されません。/deletes-これらのアクションには常にロックが必要です。

9
Philip Kelley

私にとって、トランザクションで単一のステートメントをラップするということは、たとえば手動で1回限りのUPDATEステートメントを実行するときにWHERE句を忘れた場合に、それをロールバックできるということです。数回助かった。

例えば.

--------------------------------------------------------------
CREATE TABLE T1(CPK INT IDENTITY(1,1) NOT NULL, Col1 int, Col2 char(3));
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');
INSERT INTO T1 VALUES (101, 'abc');

SELECT * FROM T1


--------------------------------------------------------------
/* MISTAKE SCENARIO     (run each row individually) */
--------------------------------------------------------------
BEGIN TRAN YOUR_TRANS_NAME_1;   /* open a trans named YOUR_TRANS_NAME_1 */
    UPDATE T1 SET COL2 = NULL;  /* run some update statement */
    SELECT * FROM T1;       /* OOPS ... forgot the where clause */
ROLLBACK TRAN YOUR_TRANS_NAME_1;    /* since it did bad things, roll it back */
    SELECT * FROM T1;       /* tans rolled back, data restored. */



--------------------------------------------------------------
/* NO MISTAKES SCENARIO (run each row individually) */
--------------------------------------------------------------

BEGIN TRAN YOUR_TRANS_NAME_2;
    UPDATE T1 SET COL2 = 'CBA' WHERE CPK = 4;   /* run some update statement */
    SELECT * FROM T1;               /* did it correctly this time */

COMMIT TRAN YOUR_TRANS_NAME_2           /* commit (close) the trans */

--------------------------------------------------------------

DROP TABLE T1

--------------------------------------------------------------
4
GWR

1つの可能性のある言い訳は、単一のステートメントがトリガーを介して他の多くのSQLを実行させる可能性があり、そこで何かがうまくいかないのを防ぐことですが、どのDBMSでも暗黙のトランザクションを使用するという常識があると思いますすでに同じ方法。

私が考えることができるもう1つのことは、一部のAPIでは自動コミットを無効にすることができ、誰かがそうした場合に備えてコードが記述されていることです。

2
user42092

明示的なトランザクションを開始してDMLを発行すると、ステートメントによってロックされているリソースはロックされたままとなり、ステートメントを手動でコミットまたはロールバックするまで、ステートメントの結果はトランザクションの外部からは見えません。

これは、必要な場合と不要な場合があります。

たとえば、ロックをかけたまま、予備の結果を外部に表示したい場合があります。

この場合、最初のトランザクションがコミットする前にロックリクエストを発行する別のトランザクションを開始し、競合状態を回避します。

暗黙的なトランザクションは、DMLステートメントが完了または失敗した直後にコミットまたはロールバックされます。

2
Quassnoi

SQL Serverには、セッションの自動コミットをオフにできる設定があります。一部のクライアントのデフォルトです( https://docs.Microsoft.com/en-us/sql/t-sql/statements/set-implicit-transactions-transact-sql?view=sql-serverを参照)。 -2017

使用するフレームワークやデータベースクライアントによっては、個々のコマンドを独自のトランザクションに入れない場合、それらがすべてデフォルトのトランザクションにまとめられることがあります。それらのそれぞれをトランザクションで明示的にラップすると、意図が明確に宣言され、現在の自動コミット設定に関係なく、プログラマーが意図した方法で実行されることが確認されます(特に、自動コミットに関する全社的なポリシーがない場合)。

データベースでbegin tran/commit tranコマンドが監視されている場合(コメント here による)、フレームワークが疑いを持たないプログラマーのためにそれらを生成している可能性もあります。 (フレームワークによって生成されたSQLコードを綿密に検査する開発者は何人いますか?)

質問がいくぶん古くからあるにもかかわらず、これがまだ適切であることを願っています。

1
Martin Vajsar