102

分離レベルを指定できるように、トランザクション内で実行する読み取りクエリがあります。クエリが完了したら、どうすればよいですか?

  • トランザクションをコミットする
  • トランザクションをロールバックする
  • 何もしない (これにより、using ブロックの最後でトランザクションがロールバックされます)

それぞれを行うことの意味は何ですか?

using (IDbConnection connection = ConnectionFactory.CreateConnection())
{
    using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
    {
        using (IDbCommand command = connection.CreateCommand())
        {
            command.Transaction = transaction;
            command.CommandText = "SELECT * FROM SomeTable";
            using (IDataReader reader = command.ExecuteReader())
            {
                // Read the results
            }
        }

        // To commit, or not to commit?
    }
}

編集:問題は、トランザクションを使用する必要があるかどうか、またはトランザクションレベルを設定する他の方法があるかどうかではありません。問題は、何も変更しないトランザクションがコミットまたはロールバックされることで違いが生じるかどうかです。性能差はありますか?他の接続に影響はありますか? 他に違いはありますか?

4

12 に答える 12

54

あなたはコミットします。限目。他に賢明な代替手段はありません。トランザクションを開始した場合は、それを閉じる必要があります。コミットすると、持っていた可能性のあるすべてのロックが解放され、ReadUncommitted または Serializable 分離​​レベルと同様に適切です。暗黙のロールバックに依存することは、おそらく技術的には同等ですが、悪い形です。

それでも納得できない場合は、コードの途中に更新ステートメントを挿入し、発生した暗黙のロールバックを追跡してデータを削除する必要がある次の人を想像してみてください。

于 2008-11-21T21:47:08.310 に答える
33

何も変更していない場合は、COMMIT または ROLLBACK を使用できます。どちらも、取得した読み取りロックを解放します。他に変更を加えていないため、それらは同等になります。

于 2008-11-21T19:22:32.377 に答える
7

トランザクションを開始する場合、ベスト プラクティスは常にコミットすることです。use(transaction) ブロック内で例外がスローされた場合、トランザクションは自動的にロールバックされます。

于 2008-11-21T19:17:19.157 に答える
3

私見では、読み取り専用クエリをトランザクションでラップすることは理にかなっています(特にJavaでは)トランザクションを「読み取り専用」にすることができます。これにより、JDBCドライバーはクエリの最適化を検討できます(ただし、そうする必要はないので、だれもINSERTそれでも発行できなくなります)。たとえば、Oracleドライバは、読み取り専用とマークされたトランザクションでのクエリのテーブルロックを完全に回避します。これにより、読み取り駆動型のアプリケーションで多くのパフォーマンスが得られます。

于 2009-03-25T09:33:25.783 に答える
2

余談ですが、次のようにコードを書くこともできます。

using (IDbConnection connection = ConnectionFactory.CreateConnection())
using (IDbTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
using (IDbCommand command = connection.CreateCommand())
{
    command.Transaction = transaction;
    command.CommandText = "SELECT * FROM SomeTable";
    using (IDataReader reader = command.ExecuteReader())
    {
        // Do something useful
    }
    // To commit, or not to commit?
}

また、少しだけ再構築すると、IDataReader の using ブロックも上部に移動できる場合があります。

于 2008-11-21T19:15:29.520 に答える
1

ROLLBACK は主にエラーまたは例外的な状況の場合に使用され、COMMIT は正常に完了した場合に使用されます。

重要ではないように見える読み取り専用トランザクションの場合でも、COMMIT (成功の場合) および ROLLBACK (失敗の場合) でトランザクションを閉じる必要があります。実際、一貫性と将来性のために重要です。

読み取り専用トランザクションは、多くの点で論理的に「失敗」する可能性があります。次に例を示します。

  • クエリが期待どおりに正確に 1 つの行を返さない
  • ストアド プロシージャが例外を発生させる
  • フェッチされたデータに一貫性がないことが判明しました
  • 時間がかかりすぎるため、ユーザーはトランザクションを中止します
  • デッドロックまたはタイムアウト

COMMIT と ROLLBACK が読み取り専用トランザクションに適切に使用されている場合、キャッシング、監査、または統計などのために DB 書き込みコードが追加された場合でも、期待どおりに機能し続けます。

暗黙的な ROLLBACK は、「致命的なエラー」の状況、つまり、アプリケーションが回復不能なエラー、ネットワーク障害、電源障害などでクラッシュまたは終了する場合にのみ使用する必要があります。

于 2015-09-08T10:05:23.433 に答える
1

SQL をストアド プロシージャに入れ、これをクエリの上に追加すると、次のようになります。

set transaction isolation level read uncommitted

そうすれば、C# コードで面倒なことをする必要はありません。ストアド プロシージャでトランザクション分離レベルを設定しても、その接続の将来のすべての使用に設定が適用されるわけではありません (接続がプールされているため、他の設定で注意する必要があります)。ストアド プロシージャの最後に、接続が初期化されたものに戻ります。

于 2008-11-21T21:45:37.517 に答える
0

READ が状態を変更しないことを考えると、私は何もしません。コミットを実行しても、リクエストをデータベースに送信するサイクルが無駄になる以外は何もしません。状態が変化した操作を実行していません。ロールバックについても同様です。

ただし、必ずオブジェクトをクリーンアップし、データベースへの接続を閉じる必要があります。このコードが繰り返し呼び出されると、接続を閉じないと問題が発生する可能性があります。

于 2008-11-21T19:14:01.567 に答える
-3

他の人が同じデータを読み取れないようにする必要がありますか? トランザクションを使用する理由

@Joel - 私の質問は、「なぜ読み取りクエリでトランザクションを使用するのですか?」という表現の方が適切でしょう。

@Stefan - ストアド プロシージャではなく AdHoc SQL を使用する場合は、クエリのテーブルの後に WITH (NOLOCK) を追加するだけです。この方法では、トランザクションのアプリケーションとデータベースで (最小限ではありますが) オーバーヘッドが発生することはありません。

SELECT * FROM SomeTable WITH (NOLOCK)

編集 @ コメント 3: 質問タグに「sqlserver」が含まれていたため、MSSQLServer がターゲット製品であると想定していました。その点が明確になったので、タグを編集して特定の製品参照を削除しました.

そもそもなぜあなたが読み取り操作でトランザクションを作成したいのか、私にはまだわかりません。

于 2008-11-21T19:15:20.957 に答える
-3

あなたが持っているあなたのコードサンプルで

  1. // 何か役に立つことをする

    データを変更する SQL ステートメントを実行していますか?

そうでない場合、「読み取り」トランザクションなどはありません...挿入、更新、および削除ステートメント(データを変更できるステートメント)からの変更のみがトランザクションにあります...あなたが話しているのは、SQLがロックすることですサーバーは、そのデータに影響を与えるその他のトランザクションのために、読み取っているデータを置きます。これらのロックのレベルは、SQL Server 分離レベルによって異なります。

ただし、SQL ステートメントが何も変更されていない場合は、何かをコミットしたり ROll Back したりすることはできません。

データを変更している場合は、トランザクションを明示的に開始せずに分離レベルを変更できます...個々の SQL ステートメントはすべて暗黙的にトランザクション内にあります。トランザクションを明示的に開始する必要があるのは、2 つ以上のステートメントが同じトランザクション内にあることを確認するためだけです。

トランザクション分離レベルを設定するだけの場合は、コマンドの CommandText を「Set Transaction Isolation level Repeatable Read」(または任意のレベル) に設定し、CommandType を CommandType.Text に設定して、コマンドを実行します。( Command.ExecuteNonQuery() を使用できます)

注: 複数の読み取りステートメントを実行していて、それらすべてに最初のステートメントと同じデータベースの状態を「表示」させたい場合は、分離レベルを top Repeatable Read または Serializable... に設定する必要があります。

于 2008-11-21T19:19:25.457 に答える