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