トップ回答者
SqlClientConnectionで、SQLServerから正常なデータが返されない。

質問
-
原因不明な現象に悩まされており、お助け下さい。
【環境】
・サーバー
Windows2012
SQLServer 2014
・クライアント
WindowsCE Compact 7
・開発環境
Visual Studio 2008 SP1
【現象】
100台近いWindowsCE端末で、日々在庫の管理をしています。
在庫が移動した時に、元在庫の在庫数を0にして、移動先の在庫数を登録する処理を行っていますが、
月に4,5回の頻度で元在庫の情報を取得するSQLの結果が、データベースの内容と一致しない事があります。
一致しないと言うのは、データが存在するのに、DataAdapter.Fill()メソッドで取得されたDataTableの結果が0件になるのです。
また、この現象が発生した時、プログラムで開始したBeginTransactionが、意図しない所で RollBack 又は、Commitが行われます。
(正常にBeginTransactionが行われなかった可能性もあるかと・・)
その為、明示的に記述した Commit処理で「SqlException:COMMIT TRANSACTION 要求に対応する BEGIN TRANSACTION がありません」が発生します。この時のInnerExceptionは「InvalidOperationException:This SqlTransaction has completed; it is no longer usable.」です。
このエラーが発生した時、INSERT、UPDATEしたデータがSQLServerに登録されている事から、
①DBの接続のOpen時
②BeginTransactionを行った時
③INSERT等の前のSELECT文を発行した時
のどこかのタイミングで、SQLServerへの接続に問題が発生していると思われます。
ただ、Exceptionが発生しない為、プログラム側で対応が取れません。
何か、情報をお持ちの方や、SQLServerで何を調べれば良いかなど、調査方法をご存じの方が居ましたら、アドバイスを頂きたいと思います。
よろしくお願いいたします。
【プログラム(プログラムをそのまま載せれませんでしたので、簡略化してあります。)】
Dim conn As New SqlClient.SqlConnection("Data Souce=・・・")
Dim dc As System.Data.SqlClient.SqlCommand
Dim da As New SqlClient.SqlDataAdapter()
Dim trn as New SqlClient.SqlTransaction()
Dim dt as New DataTable
conn.Open()
Try
'トランザクションの開始
trn.BeginTransaction()
'-- 在庫状況情報出力ログ --
sql = "SELECT * FROM E_在庫 WHERE 品目CD = 'AAAA'"
dc = New System.Data.SqlClient.SqlCommand(conn, sql, trn)
da = New SqlClient.SqlDataAdapter(dc)
da.Fill(dt)
'-- 在庫の存在するデータの取得 --
sql = "SELECT * FROM E_在庫 WHERE 品目CD = 'AAAA' AND 在庫数 > 0 ORDER BY 更新日時 DESC"
dc = New System.Data.SqlClient.SqlCommand(conn, sql, trn)
da = New SqlClient.SqlDataAdapter(dc)
da.Fill(dt)
'出庫情報の更新
sql = "UPDATE E_在庫 ・・・"
dc = New System.Data.SqlClient.SqlCommand(conn, sql, trn)
dc.ExecuteNonQuery()
dc.Dispose()
'出庫履歴情報の登録
sql = "INSERT INTO E_在庫履歴 ・・・"
dc = New System.Data.SqlClient.SqlCommand(conn, sql, trn)
dc.ExecuteNonQuery()
dc.Dispose()
'入庫情報の登録
sql = "INSERT INTO E_在庫 ・・・"
dc = New System.Data.SqlClient.SqlCommand(conn, sql, trn)
dc.ExecuteNonQuery()
dc.Dispose()
'入庫履歴情報の登録
sql = "INSERT INTO E_在庫履歴 ・・・"
dc = New System.Data.SqlClient.SqlCommand(conn, sql, trn)
dc.ExecuteNonQuery()
dc.Dispose()
'コミット
trn.Commit()
Catch ex As Exception
'ロールバック
trn.Rollback()
Finally
'オブジェクトの終了
dc.Close()
End Try
回答
-
遅くなり、すみません。
>1205等のエラーが返されない事がある事もあるのでしょうか?
基本的に以下の文書を読む限り、無いんじゃないかと思います。1205が返される場合は、自動でロールバックされるので、その際にはコードで明にロールバックの処理を実行していないサンプルが以下に載っています。
Microsoft .NET を使ったデータベース トランザクションの実装
https://msdn.microsoft.com/ja-jp/library/ms954625.aspxまた、以下も参考にしてみて下さい。
(参考)
デッドロックの検出と終了
https://technet.microsoft.com/ja-jp/library/ms178104(v=sql.105).aspxデッドロックの処理
https://technet.microsoft.com/ja-jp/library/ms177453(v=sql.105).aspxなお、デッドロックの調査に関して、いくつか検索してみましたのでご紹介しておきます。
SQL Server でデッドロックを監視するには
http://d.hatena.ne.jp/matu_tak/20091027/12565693362009-10-29 SQL Server でデッドロックの監視 その2
http://d.hatena.ne.jp/matu_tak/20091029/12567486492009-10-30 SQL Server でデッドロックの監視 その3
http://d.hatena.ne.jp/matu_tak/20091030SQL Server でトレース フラグ 1204 でデッドロックを監視する
http://d.hatena.ne.jp/matu_tak/20091031/1256915952デッドロックの状態を取得する
http://d.hatena.ne.jp/seki-moto/20101117/DeadLock2008-03-07 [DB]SQLServerProfilerでデッドロックの図示
http://d.hatena.ne.jp/iad_otomamay/20080307[SQLServer]デッドロックを発生させてログを拾ってみる
http://t-wata.com/?p=221#さて、ここはフォーラムですので、質問がある場合は誰かに限定して尋ねるよりも、広く回答を募る方が迅速、かつ良質の回答が得やすいです。
(例)
trapemiya様からご回答をいただいて調査したのですが、一つ疑問が出て来ました。以下の質問に関して、おわかりの方がいらっしゃいましたら、ご回答の程、よろしくお願いいたします。MS - 文書番号: 832524を確認致しましたが、・・・・・(略)
★良い回答には回答済みマークを付けよう! MVP - .NET http://d.hatena.ne.jp/trapemiya/
-
原因が色々と判明しましたので、ご報告になります。
SQLServerのトレースを取って確認をした所、該当する現象が発生する時に「デッドロック」が発生しておりました。
その為、デッドロック発生直後にSQLServerにより「ROLLBACK」がされておりました。
これにより、CommitメソッドでSqlException:COMMIT TRANSACTION が発生した様です。
デッドロックが発生しても例外にならなかった件ですが、「Windows Embedded Version 7.00(ビルド 2806)」に限った事かもしれませんが、SqlClient.SqlDataAdapter.Fillメソッドで、デッドロックが例外にならない事が判明しました。
Windowsアプリでは、デッドロックは例外になり、WindowsCEのSqlClient.SqlCommand.ExecuteNonQueryメソッドでもデッドロックが例外になりました。よって、WindowsCEのFrameworkのバグか何かかと思います。
皆様、色々ありがとうございました。
- 回答としてマーク ryoukai8 2015年3月20日 7:01
すべての返信
-
佐祐理様、trapemiya様 ご返信ありがとうございます。
佐祐理様
ご指摘の部分は、現在のソースコードが直接表示出来ない為、
こちらで変更を加えた部分になります。
ご指摘の通り、SqlTransactionはNew出来ないですね。
現在、日に2000件の在庫移動処理がされていますので、
処理としては問題は無いと考えております。
trapemiya様
> トランザクションの既定の分離レベルは把握されていますか?
> 感覚としては、デッドロックが怪しそうな気がします。
> デッドロックの調査の仕方はいくつかありますので、とりあえず調べられて、都合の良いものを採用して下さい。
トランザクションの分離レベルですが、把握していません。
規定値のままセットアップしてありますので、確認をしてみます。
デッドロックですが、こちらもログを拾えるようにして確認してみたいと思います。
-
遅くなり、すみません。
>1205等のエラーが返されない事がある事もあるのでしょうか?
基本的に以下の文書を読む限り、無いんじゃないかと思います。1205が返される場合は、自動でロールバックされるので、その際にはコードで明にロールバックの処理を実行していないサンプルが以下に載っています。
Microsoft .NET を使ったデータベース トランザクションの実装
https://msdn.microsoft.com/ja-jp/library/ms954625.aspxまた、以下も参考にしてみて下さい。
(参考)
デッドロックの検出と終了
https://technet.microsoft.com/ja-jp/library/ms178104(v=sql.105).aspxデッドロックの処理
https://technet.microsoft.com/ja-jp/library/ms177453(v=sql.105).aspxなお、デッドロックの調査に関して、いくつか検索してみましたのでご紹介しておきます。
SQL Server でデッドロックを監視するには
http://d.hatena.ne.jp/matu_tak/20091027/12565693362009-10-29 SQL Server でデッドロックの監視 その2
http://d.hatena.ne.jp/matu_tak/20091029/12567486492009-10-30 SQL Server でデッドロックの監視 その3
http://d.hatena.ne.jp/matu_tak/20091030SQL Server でトレース フラグ 1204 でデッドロックを監視する
http://d.hatena.ne.jp/matu_tak/20091031/1256915952デッドロックの状態を取得する
http://d.hatena.ne.jp/seki-moto/20101117/DeadLock2008-03-07 [DB]SQLServerProfilerでデッドロックの図示
http://d.hatena.ne.jp/iad_otomamay/20080307[SQLServer]デッドロックを発生させてログを拾ってみる
http://t-wata.com/?p=221#さて、ここはフォーラムですので、質問がある場合は誰かに限定して尋ねるよりも、広く回答を募る方が迅速、かつ良質の回答が得やすいです。
(例)
trapemiya様からご回答をいただいて調査したのですが、一つ疑問が出て来ました。以下の質問に関して、おわかりの方がいらっしゃいましたら、ご回答の程、よろしくお願いいたします。MS - 文書番号: 832524を確認致しましたが、・・・・・(略)
★良い回答には回答済みマークを付けよう! MVP - .NET http://d.hatena.ne.jp/trapemiya/
-
-
原因が色々と判明しましたので、ご報告になります。
SQLServerのトレースを取って確認をした所、該当する現象が発生する時に「デッドロック」が発生しておりました。
その為、デッドロック発生直後にSQLServerにより「ROLLBACK」がされておりました。
これにより、CommitメソッドでSqlException:COMMIT TRANSACTION が発生した様です。
デッドロックが発生しても例外にならなかった件ですが、「Windows Embedded Version 7.00(ビルド 2806)」に限った事かもしれませんが、SqlClient.SqlDataAdapter.Fillメソッドで、デッドロックが例外にならない事が判明しました。
Windowsアプリでは、デッドロックは例外になり、WindowsCEのSqlClient.SqlCommand.ExecuteNonQueryメソッドでもデッドロックが例外になりました。よって、WindowsCEのFrameworkのバグか何かかと思います。
皆様、色々ありがとうございました。
- 回答としてマーク ryoukai8 2015年3月20日 7:01