Dav*_*der 8 sql-server ado.net transaction azure-sql-database
我正在尝试在我的应用程序中实现事务。我只是想像 BeginTransaction() 文档中显示的示例一样实现它。
Public Shared Sub Process(wwid As String, trade_id As Integer, disposition As Boolean)
Dim q As String
Dim cmd, cmd_select As SqlCommand
Dim reader As SqlDataReader
Dim trans As SqlTransaction
Dim user_id As Integer = User.CheckAuthentication(wwid)
If user_id > 0 Then
Using conn As New SqlConnection(CNGDB)
conn.Open()
'1. ReadUncommitted
'2. ReadCommitted
'3. RepeatableRead
'4. Serializable
'5. Snapshot
trans = conn.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted)
Try
q = "UPDATE Trades SET Disposition = @disposition, FinalizedAt = @finalized_at" & _
" WHERE TradeID = @trade_id"
cmd = New SqlCommand(q, conn)
cmd.Transaction = trans
cmd.Parameters.AddWithValue("@disposition", disposition)
cmd.Parameters.AddWithValue("@finalized_at", DateTime.Now)
cmd.Parameters.AddWithValue("@trade_id", trade_id)
cmd.ExecuteNonQuery()
If disposition = True Then
q = "SELECT Ownership_OwnershipID, Recipient_UserID FROM Trades" & _
" WHERE TradeID = @trade_id"
cmd_select = New SqlCommand(q, conn)
cmd_select.Transaction = trans
cmd_select.Parameters.AddWithValue("@trade_id", trade_id)
reader = cmd_select.ExecuteReader
reader.Read()
q = "UPDATE Ownerships SET User_UserID = @recipient_id" & _
" WHERE OwnershipID = @ownership_id"
cmd = New SqlCommand(q, conn)
cmd.Transaction = trans
cmd.Parameters.AddWithValue("@recipient_id", reader("Recipient_UserID"))
cmd.Parameters.AddWithValue("@ownership_id", reader("Ownership_OwnershipID"))
cmd.ExecuteNonQuery()
End If
trans.Commit()
Catch ex As Exception
Console.WriteLine("Commit Exception Type: {0}", ex.GetType())
Console.WriteLine(" Message: {0}", ex.Message)
Try
trans.Rollback()
Catch ex2 As Exception
Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType())
Console.WriteLine(" Message: {0}", ex2.Message)
End Try
End Try
End Using
End If
End Sub
Run Code Online (Sandbox Code Playgroud)
问题是,每当它遇到 Commit() 时,我都会收到错误消息:
提交异常类型:System.Data.SqlClient.SqlException
消息:无法执行事务操作,因为有处理此事务的待处理请求。
我希望问题在于我试图从 中读取SELECT
以填充第二个中的值UPDATE
,但我不知道还能怎么做。我已经尝试将数据库IsolationLevel设置为其他一些值,但它没有改变任何东西。
我还找到了TransactionScope类,并为此代码实现了它的示例。但是,当我尝试将该技术应用于一组更复杂的操作时,它抱怨无法与我本地计算机的分布式事务服务器通信。我打开它,DTS 取消了另一个更复杂的事务,出于某种未指明的原因,我不想掉进那个兔子洞。
谁能指出我在代码中做错了什么?
此外,在 .NET 程序中包装一组 SQL 操作的正确方法是什么?也许 DTS 是更好的方法,但是这个应用程序最终会存在于 Azure 数据库中,而且 Azure 似乎无论如何都不支持 DTS,尽管有一些关于隔离级别的“自动升级”的说法,我很困惑.
为了速度,我在这个应用程序中简单地使用了存储过程,但发现它并没有更快,并决定我不想尝试维护数据库中的任何代码。相反,我希望将我的数据库访问库与我的 GUI 前端应用程序(在 VB 中)一起保留在 Visual Studio 中,以便(主要是)在一个地方处理它。
首先,我完全同意Aaron Bertrand在评论中建议您将 SQL 移到存储过程中。顺便说一下,这也是“在 .NET 程序中包装一组 SQL 操作的正确方法”的明显赢家。
由于您担心在两个地方管理代码,因此您应该查看Visual Studio 中的数据库项目。我已经使用了一段时间了,它的效果非常好。当你走这条路时,你甚至会得到一些方便但有限的重构工具。
我发现您的 Visual Basic 代码存在几个问题:
cmd
when disposition = True
,而不是使用另一个变量。我不确定,但我相信,这将阻止事务回滚初始更新。无论如何,这在我看来不是最佳实践。.AddWithValue()
方法。如这篇博文 中所述,您可能会因隐式转换而遇到问题。另外,SqlDataReader
按照Magoo 先生在评论中的建议并在您的评论中确认的关闭工作的原因也是因为读者正在阻止连接上发生任何其他事情,直到它关闭。这是文档中的引用:
在使用SqlDataReader 的同时,关联的SqlConnection 正忙于为SqlDataReader 服务,除了关闭SqlConnection 之外,无法对SqlConnection 执行其他操作。在调用 SqlDataReader 的 Close 方法之前都是这种情况。例如,只有在调用 Close 之后才能检索输出参数。
有关可能由您使用/滥用读者的方式引起的更多/相关恶作剧,请查看Stack Overflow 上的这个答案。
根据您的评论还有一些想法:
填充在数据库已经存在之后创建的数据库项目的一种简单方法是使用“模式比较”功能。在我的 Visual Studio 版本中,此功能位于以下菜单栏中:工具 --> SQL Server --> 新架构比较。您可能需要为您的 Visual Studio 版本下载最新版本的 SSDT(免费)才能获得此功能。
我同意您可能不应该在接下来的几周内将内联 SQL 转移到存储过程中。正如我在过去提到的,在重构应用程序的核心元素时阻止更新很少是最好的计划。您可以选择将所有新数据访问移到存储过程中,并在必须接触内联 SQL 时决定将 SQL 移到存储过程中。这将是微创的,随着时间的推移展开工作,并允许您系统地改进您的代码库(VB.NET和SQL)。
归档时间: |
|
查看次数: |
4893 次 |
最近记录: |