SqlClient.SqlConnectionでDB接続からデータ取得。完全なClose処理まで

諸事情でVBなのでC#の人は適宜読み替えて。





Public Shared Sub ExecuteOnce(query As String)

   Dim CONNECTION_STRING = "ServerName=DESKTOP-XXXXXX\SQLEXPRESS, Database=testdb;User ID=sa;Password=sa"
   Dim result As String = ""
   Dim query As String = "Select * From TestTable"
   Dim connection As SqlClient.SqlConnection = Nothing
   Dim tran As SqlClient.SqlTransaction = Nothing
   Dim command As SqlClient.SqlCommand = Nothing
   Dim reader As SqlClient.SqlDataReader = Nothing
   Try
       connection = New SqlClient.SqlConnection(CONNECTION_STRING)
       connection.Open()

       tran = connection.BeginTransaction()

       command = connection.CreateCommand()
       command.CommandText = query
       command.Transaction = tran
       reader = command.ExecuteReader()

       While reader.Read
           'レコードの最初の項目を出力
           Debug.WriteLine(reader(0).ToString)
       End While
       reader.Close()
       tran.Commit()

   Catch
       If tran IsNot Nothing Then
           tran.Rollback()
       End If

   Finally
       If reader IsNot Nothing Then
           reader.Close()
           reader.Dispose()
       End If
       If tran IsNot Nothing Then
           tran.Dispose()
       End If
       If command IsNot Nothing Then
           command.Dispose()
       End If
       If connection IsNot Nothing Then
           connection.Close()
           connection.Dispose()
       End If

   End Try

 End Sub


SqlDataReaderはIDisposableを実装しているのでUsing句が使えるのだがネストが増えるくらいであまり使う意味はない気がする。
C#だとSqlConnectionなども持ってる?無限にネストが深くなるような気がする。
と思ったらこんな書き方もできるのか、C#はこっちのほうがスマートかも(2番目くらいのアンサー)
https://stackoverflow.com/questions/16985876/sqlconnection-sqlcommand-sqldatareader-idisposable

どのタイミングでFinallyが呼ばれるかわからないためNothingの確認をする。
SqlClient.SqlTransactionのCommitは2回呼ぶと落ちる(Rollbackも同様)。必ずBeginTransactionと1:1で対応付ける。
トランザクションコミット前にSqlDataReaderをCloseしないといけない。コミット後に読まれるのを防ぐためだろう。
Dispose()やClose()は何度呼んでも落ちない。がわかりやすさのためFinally句ですべて処理する。
終了時はClose, Disposeの順にメソッドがあれば呼ぶ。対称になるように順に呼んでいく。


参考
http://surferonwww.info/BlogEngine/post/2013/04/23/whether-to-call-dispose-method-for-sqlcommand-object.aspx



このくらいやればリークは起きないと思われる。情報なさすぎでつらい。
.netって目眩がするようなコードが散乱してるよね。

2018年9月13日木曜日