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って目眩がするようなコードが散乱してるよね。