明らかに間違った分離レベルで実行されるいくつかのデータベース コードに問題があります。コードのこの特定の部分では、ロックを最小限に抑えるために「READ UNCOMMITTED」で実行することになっています。この時点では、不整合なデータは問題ありません。
ただし、コードは実際には READ COMMITTED で読み取りますが、その理由はわかりません。
行ったことは次のとおりです。
- 接続を開く
- この接続で「SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED」を実行します
- ブレークポイントにヒット
- SQL を実行する
ブレークポイントで、次のコマンドをデータベースに発行します。
select s.session_id, s.transaction_isolation_level, st.text from sys.dm_exec_sessions s
inner join sys.sysprocesses sp on (sp.spid = s.session_id)
CROSS APPLY sys.dm_exec_sql_text(sp.sql_handle) st
この SQL は現在 4 つのプールされた接続を報告します。そのうちの 1 つは、ブレークポイントを超えて SQL を実行できる接続で、次の状態です。
53 2 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
すなわち。セッション 53 には分離レベル 2 (READ COMMITTED) があり、このセッションで最後に実行された SQL はその「SET TRANSACTION ...」コマンドでした。
どうすればいいの?
.NET コードが開く前にこの接続が有効でなかったことを SQL プロファイラーで確認したため、接続プールから再利用されませんでした。
しかし、接続が新しくなり、その接続で実行された最初の唯一の SQL が明示的に READ UNCOMMITTED を使用するように指示した場合、接続が依然として READ COMMITTED である可能性はありますか?
ここで何を見るべきですか?
接続文字列 (編集されたビットを含む) は次のようになります。
SERVER=hostname;DATABASE=dbname;Integrated Security=false;USER ID=sa;PASSWORD=****;Application Name=appname;Type System Version=SQL Server 2000;Workstation ID=hostname;
接続は通常のSqlConnection
接続であり、通常の方法で開かれます。
残念ながら、SqlConnection を開く通常のコードを記述しても問題を再現できないため、アプリケーションの状態に何らかの問題があるはずですが、SqlProfiler と Sql Server の両方が「はい、SQL は実行されましたが、いいえ、私は気にしないでください。
これには何が影響しますか?
まったく同じコードが他の接続も開きます。つまり、コードが何度も実行され、多くの接続が開かれるため、複数の接続がプールに入れられますが、この問題が発生するのは最初の接続だけです。
これは SQL Server 2008 R2 であり、2012 でもこの問題を再現しました。
編集
OK、もう少し情報。
まず、プーリングを有効にしています。つまり、明示的に無効にしておらず、接続文字列をいじって「N」個のプールを作成していません。
ただし、この接続は、この特定の接続文字列で最初に開かれるため、プールから取得されません。また、永久に「病気」であるという以下の私のメモも参照してください。
この接続は次のように設定されています。
var conn = new SqlConnection(...);
conn.StateChance += connection_StateChange;
private void connection_StateChange(Object sender, StateChangeEventArgs e)
{
if (e.CurrentState == ConnectionState.Open)
{
using (IDbCommand cmd = ((SqlConnection)sender).CreateCommand())
{
cmd.CommandText = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
cmd.ExecuteNonQuery();
}
これより前に他の SQL を実行していません。
このコードは、アプリケーションの存続期間中に何度も使用されることに注意してください。最終的に間違っているのは、最初に開いた接続のみです。
この接続も永久に病気になります。接続を開くたびに (接続プールから取得する場合でも)、上記の状態変更イベントが実行され、分離レベルを再度設定しようとします。これも失敗しますが、この単一の接続のみです。
さらに、この質問を投稿してから、これに影響を与える 1 つのことがわかりました。
上に投稿した接続文字列を変更することにより:
...;Type System Version=SQL Server 2000;...
これに:
...;Type System Version=SQL Server 2008;MultipleActiveResultSets=true;...
その後、この問題はなくなります。前述のブレークポイントで、接続は「READ UNCOMMITTED」状態になります。
これはおせっかいでした。実際にコードを実行するまで、概要で接続が報告されませんでした。
デバッグを続けています。