1

以下のコードを参照してください。

Private Sub TransactionExample3()
        Dim objDR As SqlDataReader
        Dim objCommand As SqlCommand, objCommand2 As SqlCommand
        Dim objCon As SqlConnection
        Dim objCon2 As SqlConnection
        Dim id As Integer
        Dim list As List(Of Integer) = New List(Of Integer)
        Try
            _ConString = "Data Source=databaseserver;Initial Catalog=Person;User ID=username;Password=password;MultipleActiveResultSets=True"
            list.Add(1)
            list.Add(2)
            list.Add(3)

            For Each i As Integer In list
                Using trans = New TransactionScope()
                    objCon2 = New SqlConnection(_ConString)
                    objCon2.Open()
                    objCommand2 = New SqlCommand()
                    objCommand2.Connection = objCon2
                    Using objCon2
                        objCommand2.CommandText = "UPDATE Person SET forenames = @forenames WHERE " & _
                            " Reference = @Reference "
                        objCommand2.Parameters.AddWithValue("@forenames", i + 1)
                        objCommand2.Parameters.AddWithValue("@Reference", i)
                        objCommand2.ExecuteNonQuery()
                        objCommand2.Parameters.Clear()
                    End Using
                    trans.Complete()
                End Using
            Next

        Catch ex As Exception
            Throw
        Finally

        End Try

    End Sub

このコードは機能します。つまり、各ループで変更がデータベースにコミットされます。

以下のコードをご覧ください。

Private Sub TransactionExample3()
        Dim objDR As SqlDataReader
        Dim objCommand As SqlCommand, objCommand2 As SqlCommand
        Dim objCon As SqlConnection
        Dim objCon2 As SqlConnection
        Dim id As Integer
        Try
            _ConString = "Data Source=server;Initial Catalog=Person;User ID=Username;Password=Password;MultipleActiveResultSets=True"
            objCon = New SqlConnection(_ConString)
            objCommand = New SqlCommand("SELECT top 10 * from Person")
            objCommand.Connection = objCon
            objCon.Open()
            objDR = objCommand.ExecuteReader()
            Do While objDR.Read
                objCon2 = New SqlConnection(_ConString)
                objCon2.Open()
                Using trans = New TransactionScope()
                    objCommand2 = New SqlCommand()
                    objCommand2.Connection = objCon
                    Using objCon2
                        objCommand2.CommandText = "UPDATE Person SET forenames = @forenames WHERE " & _
                            " Reference = @Reference "
                        objCommand2.Parameters.AddWithValue("@forenames", objDR("Reference") + 10)
                        objCommand2.Parameters.AddWithValue("@Reference", objDR("Reference"))
                        objCommand2.ExecuteNonQuery()
                        objCommand2.Parameters.Clear()
                    End Using
                End Using
            Loop
            objDR.Close() 'line 16
        Catch ex As Exception
            Throw
        Finally

        End Try

    End Sub

2 番目のコードの抜粋では、スコープは完全ではありません (scope.complete) が、while ループの反復ごとに結果がデータベースにコミットされます。どうしてこれなの?

4

1 に答える 1

2

最初のループでは、TransactionScope の開始は、接続の開始前です。2枚目は後です。接続はトランザクションに登録されていないため、すべてのコマンドはトランザクションによって保持されることなく実行されます。

これらの行を切り替えてみてください

Do While objDR.Read
    Using trans = New TransactionScope()
       objCon2 = New SqlConnection(_ConString)
       objCon2.Open()
       .....

次に、trans.Complete() の呼び出しが必要です。

Private Sub TransactionExample3()
    Dim objDR As SqlDataReader
    Dim objCommand As SqlCommand, objCommand2 As SqlCommand
    Dim objCon As SqlConnection
    Dim objCon2 As SqlConnection
    Dim id As Integer
    _ConString = "Data Source=server;Initial Catalog=Person;User ID=Username;Password=Password;MultipleActiveResultSets=True"
    Using objCon = New SqlConnection(_ConString)
        objCommand = New SqlCommand("SELECT top 10 * from Person")
        objCommand.Connection = objCon
        objCon.Open()
        objDR = objCommand.ExecuteReader()
        Using trans = New TransactionScope()
        Using objCon2 = New SqlConnection(_ConString)
            objCon2.Open()
            Do While objDR.Read
                objCommand2 = New SqlCommand()
                objCommand2.Connection = objCon
                Using objCon2
                    objCommand2.CommandText = "UPDATE Person SET forenames = @forenames WHERE " & _
                        " Reference = @Reference "
                    objCommand2.Parameters.AddWithValue("@forenames", objDR("Reference") + 10)
                    objCommand2.Parameters.AddWithValue("@Reference", objDR("Reference"))
                    objCommand2.ExecuteNonQuery()
                    objCommand2.Parameters.Clear()
                End Using
            Loop
            objDR.Close() 'line 16
        End Using
        trans.Complete()
        End Using    
    End Using
End Sub

トランザクションと接続の開始をループの外に移動し、foreach ループの後で Complete を呼び出して接続を破棄することをお勧めします。コードを正しく理解していれば、各ループで 1 つのレコードを更新するため、トランザクションは更新する場合にのみ意味があります。あなたのすべての記録か、まったく記録がないか。もう 1 つの小さな最適化は、SqlCommand とパラメーターの作成をループの外に移動することです。各ループでパラメーター コレクションを破棄および再構築せずに、ループ内のパラメーター値のみを更新します。

于 2013-07-29T12:01:28.113 に答える