【问题标题】:SqlConnection transaction supportSqlConnection 事务支持
【发布时间】:2012-01-04 09:35:28
【问题描述】:

我正在尝试向我们的数据库对象添加事务支持。 此对象是一个远程处理对象。 (这是为了确保在 Windows 客户端上,不需要数据库连接。)

现在我想添加对事务的支持; 基本上,客户需要像这样使用它;

  1. 开始交易
  2. ExecuteNonQuery("insert...")
  3. ExecuteNonQuery("insert...")
  4. 提交/回滚


Public Function ExecuteNonQuery(ByVal Query As String) As Integer
   Dim intResult As Integer = -1
Using conn As New SqlConnection(Me.strConnectionString)
Using cmd As New SqlCommand(Query, conn)
conn.Open() intResult = cmd.ExecuteNonQuery()
End Using End Using Return intResult End Function

所以我遇到的问题是,当我在上述方法中使用新连接(using conn...)时,我无法真正创建事务。

所以我认为我需要将 SqlConnection 实例移到方法之外并将其更改为类级变量。但这不是我认为的最佳实践。 (?) 另外:按顺序执行大量查询会导致错误:“内部致命错误”。

有没有人可以指出我正确的方向?我在网上找到的所有示例都以最简单的方式通过直接按顺序执行多个查询来涵盖事务。

编辑:有点像this question(如何在 .NET 中为多个 SqlConnections 使用单个 SqlTransaction?) 。所以也许这是不可能的,但是有解决方法吗?

编辑 2: 似乎也引发了这个“内部致命错误”,因为该对象是并行使用的。也许这是不可能的?

【问题讨论】:

    标签: vb.net transactions remoting


    【解决方案1】:

    我认为您需要建立连接类级别。我要做的是检查是否已经存在连接,如果没有,则创建该连接和事务(如果需要)。跟踪它直到调用提交或回滚。我认为在这种情况下使用类级别的私有字段没有任何问题。

    类似这样的:

    Public Class SqlHandler
        Implements IDisposable
    
        Private mConnection As SqlConnection
        Private mTransaction As SqlTransaction
        Private strConnectionString As String
    
        Public Sub New()
    
        End Sub
    
        Public Sub New(UseTransaction As Boolean)
            mConnection = New SqlConnection
            If UseTransaction Then
                mTransaction = mConnection.BeginTransaction()
            End If
        End Sub
    
        Public Function ExecuteNonQuery(ByVal Query As String) As Integer
            Dim intResult As Integer = -1
    
            Using mConnection As SqlConnection
                Using cmd As New SqlCommand(Query, mConnection, mTransaction)
                    cmd.Transaction = mTransaction
                    mConnection.Open()
                    intResult = cmd.ExecuteNonQuery()
                End Using
            End Using
            Return intResult
        End Function
    
        Public Sub Commit()
          If mTransaction IsNot Nothing Then
            mTransaction.Commit()
            mTransaction.Dispose()
          End If
              mConnection.Close()
              mConnection.Dispose()
        End Sub
    
    #Region "IDisposable Support"
        Private disposedValue As Boolean ' To detect redundant calls
    
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    If mTransaction IsNot Nothing Then
                        mTransaction.Rollback()
                        mTransaction.Dispose()
                    End If
                    If mConnection IsNot Nothing Then
                        mConnection.Close()
                        mConnection.Dispose()
                    End If
                End If
            End If
            Me.disposedValue = True
        End Sub
    
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
    #End Region
    
    End Class
    

    我没有对此进行测试,但它应该能让你明白我的意思。只需确保在每种可能的情况下关闭并处理您的连接和事务即可。

    【讨论】:

    • 感谢您的评论,我已经缩小了问题的范围。这与我并行使用该对象的事实有关。这会导致问题。明天继续。
    • 在我给出的示例中,客户必须为他们希望执行的每组命令创建此对象的新实例。
    • 毕竟这是我想的路。只需要为每个线程创建一个新实例,因为并行使用根本不可能。谢谢!
    【解决方案2】:

    我觉得你可以把SqlConnection对象作为类的一个字段。

    Class SQLHelp
        Implements IDisposable
        Private ReadOnly _conn As SqlConnection
        Private _trans As SqlTransaction
    
        Public ReadOnly Property Connection As SqlConnection
            Get
                Return _conn
            End Get
        End Property
    
        Sub New(strConnectionString)
            _conn = New SqlConnection(strConnectionString)
            _trans = Nothing
        End Sub
    
        Public Function ExecuteNonQuery(ByVal Query As String) As Integer
            Dim intResult As Integer = -1
    
            If _trans Is Nothing Then
                Using cmd As New SqlCommand(Query, _conn)
    
                    If _conn.State <> ConnectionState.Open Then
                        _conn.Open()
                    End If
                    intResult = cmd.ExecuteNonQuery()
    
                End Using
            Else
                Using cmd As New SqlCommand(Query, _conn, _trans)
    
                    If _conn.State <> ConnectionState.Open Then
                        _conn.Open()
                    End If
                    intResult = cmd.ExecuteNonQuery()
    
                End Using
            End If
            Return intResult
        End Function
    
        Public Function BeginTransaction() As SqlTransaction
            _trans = _conn.BeginTransaction()
            Return _trans
        End Function
    
        Public Sub SubmitTransaction()
            If Not (_trans Is Nothing) Then
                _trans.Commit()
            End If
            _trans = Nothing
        End Sub
    
        Public Sub RollbackTransaction()
            If Not (_trans Is Nothing) Then
                _trans.Rollback()
            End If
        End Sub
    
        Public Sub Dispose() Implements IDisposable.Dispose
    
            If Not (_trans Is Nothing) Then
                _trans.Dispose()
            End If
    
            _conn.Close()
            _conn.Dispose()
    
        End Sub
    End Class
    

    在使用这个类的时候,可以试试下面的代码。

        Using _sqlHelp As New SQLHelp(connectionString)
           _sqlHelp.BeginTransaction()
           'ExecuteNonQueryCode
           _sqlHelp.Commit() 'Or _sqlHelp.Rollback()
        End Using
    

    你怎么看?

    【讨论】:

    • 感谢您的回复,但您的解决方案也不支持事务。
    • 我修改了我的代码,使它可以在事务模式下工作。请再次检查。
    • 感谢您的评论,我已经缩小了问题的范围。这与我并行使用该对象的事实有关。这会导致问题。明天继续。
    • 您的(编辑的)代码几乎类似于“D..”。正如我在他的评论中回复的那样,这似乎是要走的路。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多