我试图找出创建类的最佳方法,这样我就可以使用它连接到Server,并在存在单个错误的情况下回滚所有内容。
现在,我正在使用一个连接作为一个过程。这有时会导致我的代码抛出There is already an open DataReader associated with this Command which must be closed first.
我想为每个事务建立一个新的连接,但是如果我这样做,我不知道我是否可以回滚所有的东西。
如果存在单个错误,则调用sBDCloseConnect(True)并进行回滚并关闭连接。这很有用,因为我通常使用多个sql查询进行大量迭代。
下面是我使用的相关代码,我想知道是否有更好的方法来做到这一点,并避免抛出我前面提到的错误。
最后一点,我不想要像火星这样的解决方案。
'' Initialize connection to database
sBDInitConnect()
Dim test1 As Integer = Val(sBDReturnQuery("SELECT 1"))
If test1 < 0 Then
'' Has thrown an error
sBDCloseConnect(True)
ElseIf test1 > 1 Then
Using dt As New DataTable
Dim test2 As Integer = sBDSelectSQL("SELECT name FROM users WHERE idUser=1", dt)
If test2 < 0 Then
'' Has thrown an error
sBDCloseConnect(True)
ElseIf test2 > 0 Then
If Not sBDNonQuery("UPDATE users SET name='only a test' WHERE idUser=1") Then
sBDCloseConnect(True)
Else
If Not sBDNonQuery("UPDATE users SET name2='this field does not exist' WHERE idUser=1") Then
sBDCloseConnect(True)
End If
End If
End If
End Using
End If
'' No error
sBDCloseConnect(False)Public Partial Class componenteDEFAULT
Inherits System.Web.UI.UserControl
Private bdConection As Data.SqlClient.sqlConnection
Private bdTransaction As Data.SqlClient.sqlTransaction
Public bdCommand As Data.SqlClient.SqlCommand
Sub sBDInitConnect()
Try : bdConection.Close() : Catch : End Try
Try
bdConection = Nothing
bdConection = New Data.SqlClient.SqlConnection(bd.ConnectString)
bdConection.Open()
bdTransaction = Nothing
bdTransaction = bdConection.BeginTransaction(IsolationLevel.ReadCommitted)
bdCommand = New Data.SqlClient.SqlCommand()
bdCommand.Transaction = bdTransaction
bdCommand.Connection = bdConection
bdCommand.CommandType = CommandType.Text
bdCommand.CommandTimeout = 80
Catch ex As Exception
sErro(ex.Message)
End Try
End Sub
Function sBDSelectSQL(ByVal comando As String, ByRef rs As Data.DataTable) As Integer
If rs Is Nothing Then : rs = New DataTable : Else : rs.Clear() : End If
Try
bdCommand.Parameters.Clear()
bdCommand.CommandText = PrepareStringToDB(comando)
Using dr As Data.SqlClient.SqlDataReader = bdCommand.ExecuteReader(CommandBehavior.Default)
rs.Load(dr)
End Using
Return rs.Rows.Count
Catch ex As Exception
sErro(PrepareStringToDB(comando) & " - " & ex.Message)
Return -1
End Try
End Function
Function sBDNonQuery(ByVal comando As String) As Boolean
Try
bdCommand.Parameters.Clear()
bdCommand.CommandText = PrepareStringToDB(comando)
bdCommand.ExecuteNonQuery()
Return True
Catch ex As Exception
sErro(PrepareStringToDB(comando) & " - " & ex.Message)
Return False
End Try
End Function
Function sBDReturnQuery(ByVal comando As String) As String
Try
bdCommand.Parameters.Clear()
bdCommand.CommandText = PrepareStringToDB(comando)
Return bdCommand.ExecuteScalar()
Catch ex As Exception
sErro(PrepareStringToDB(comando) & " - " & ex.Message)
Return "-1"
End Try
End Function
Sub sBDCloseConnect(ByVal erro As Boolean)
If erro Then
Try : bdTransaction.Rollback() : Catch : End Try
Try : bdConection.Close() : Catch : End Try
Else
Try : bdTransaction.Commit() : Catch : End Try
Try : bdConection.Close() : Catch : End Try
End If
End Sub
End Class发布于 2015-09-02 14:00:06
我读了你问题的正文部分,听起来你真的是在为它做数据库的工作,如果可能的话,这总是效率低下的,如果可能的话,不要。特别是当涉及回滚事务时。
在需要执行一系列不同的查询和回滚(如果出了问题)的情况下,创建一个调用所有这些查询的存储过程。
使用SQL数据库来实现它的用途。
SQL Server擅长查询数据和对数据执行操作,它有捕获错误和回滚整个事件的方法。去做吧,从长远来看,这会容易得多。
发布于 2015-09-02 17:11:19
我试图找出创建类的最佳方法,这样我就可以使用它连接到Server,并在存在单个错误的情况下回滚所有内容。
这听起来很像事务的用途。看代码,你已经把那部分写好了.多少有点。
抽象是错误的。我首先想到的是:
Inherits System.Web.UI.UserControl为什么数据访问逻辑需要与UI控件纠缠在一起?您需要的是封装一个事务--一个“普通”类可以做到这一点,并且它的实现可以避免UI层的代码。
然后是这样的:
Private bdConection As Data.SqlClient.sqlConnection
Private bdTransaction As Data.SqlClient.sqlTransaction
Public bdCommand As Data.SqlClient.SqlCommand如果第三个字段不像大拇指一样突出:字段不应该是Public;公开的字段会破坏封装,打开代码以解决各种不必要的问题和边缘情况(例如,当事务的中间由外部代码重新分配bdCommand引用时,会发生什么情况?)
一个问题是,SqlConnection、SqlTransaction和SqlCommand类型都实现了IDisposable接口,因此应该尽可能短时间,并正确地处理:将一次性引用设置为NOTHING并不会释放它。你的类拥有这些实例,应该对它们的处理负责.它应该发生在Dispose()方法中,它似乎不会被覆盖。
现在,如果你去适当的处理那里的可处理的东西,你会遇到一些新的问题,比如ObjectDisposedException被扔遍了整个地方。其原因是,您正在重用不应该重用的对象。
封装事务的正确抽象是一个工作单元--一个简单的抽象可以如下所示:
Public Interface IUnitOfWork
Sub Commit()
Sub Execute(command As SqlCommand)
Function Select(command As SqlCommand) As DataTable
End Interface您不需要在那里使用Rollback()方法,因为如果在提交之前释放工作单元,那么就有效地取消了所有挂起的更改。我在这里添加了一个接受Execute对象的SqlCommand方法,因为我不想进入存储库,所以我的想法是公开一个可以在事务的范围内运行命令的方法。
Public Class UnitOfWork Implements IUnitOfWork, IDisposable
Private ReadOnly connection As SqlConnection
Private ReadOnly transaction As SqlTransaction
Public Sub New(connection As SqlConnection)
'' assume connection owner already opened the connection (document that!)
Me.connection = connection
Me.transaction = Me.connection.BeginTransaction(IsolationLevel.ReadCommitted)
End Sub
Public Sub Execute(command As SqlCommand)
'' assume command owner already set up parameters and cmd text (document that!)
command.Transaction = Me.Transaction
command.Connection = Me.connection
command.ExecuteNonQuery()
End Sub
Public Function Select(command As SqlCommand) As DataTable
'' assume command owner already set up parameters and cmd text (document that!)
command.Transaction = Me.Transaction
command.Connection = Me.connection
Using reader = command.ExecuteReader()
Dim result As DataTable = New DataTable
result.Load(reader)
Return result
End Using
End Function
Public Sub Commit()
Me.Transaction.Commit()
End Sub
Public Sub Dispose()
Me.Transaction.Dispose()
End Sub
End Class你可以用这样的方法:
Private Sub DoSomething(connection As SqlConnection)
Using uow = New UnitOfWork(connection)
Try
uow.Execute(GetCommandForFoo())
uow.Execute(GetCommandForBar())
uow.Commit()
Catch exception As SqlException
'' message? log? whatever...
End Try
End Using
End Sub如果您需要一个新事务,则需要一个新的UnitOfWork实例。但是,如果您做得对,那么无论如何,每个请求都不需要超过一次Commit。
PascalCase,并避免使用神秘前缀(我到处看到的毫无意义的s是什么?)sBDNonQuery返回一个Boolean。如果该命令失败,就会出现问题,您无论如何都要回滚:只需让异常冒泡起来即可。Try : bdTransaction.Commit() : Catch : End Try非常、非常、非常糟糕:如果无法提交事务,您需要知道--至少要记录一些有关它的信息。通过吞咽任何可能发生的异常,您将为以后的一些恶梦般的调试做准备。r在erro和sErro在哪里?rs是我们用来在VB6/VBA中命名ADODB.Recordset对象实例的方法。这是.NET,它是DataTable。相应地说出名字。SqlCommand模板。从LINQ开始,然后看看实体框架可以为您做什么.https://codereview.stackexchange.com/questions/90181
复制相似问题