如何通过 VB.Net 在 Azure SQL 数据库上执行完全异步查询?

How to execute a totally asynchronous query on an Azure SQL Database via VB.Net?

提问人:ProgrammerKyle 提问时间:11/9/2023 最后编辑:CraigProgrammerKyle 更新时间:11/10/2023 访问量:57

问:

我有一个连接到 Azure SQL Server 的 ASP.Net 网站。

我需要执行一个存储过程,该过程主要由插入语句组成,运行大约需要 8 分钟。

我通常会通过网站 VB.Net 代码中的 SqlCommand.ExecuteNonQuery 来执行此操作。

但是,在这种情况下,由于运行时间为 8 分钟,这样做会导致网站超时。

我需要一种方法来异步执行此查询,以便网站将命令发送到服务器并立即恢复操作,而无需等待结果。当我稍后检查相关表格时,如果出现问题,将很明显。

我无法使用 Service Broker,因为 Azure 不允许这样做,而且如果没有 Azure 托管实例,我无法设置作业。

我尝试过 SqlCommand.BeginExecuteNonQuery,它确实允许我单击代码后面的按钮,然后立即返回到网站中执行其他操作,但似乎没有实际运行查询,我猜这是因为我的代码到达事件的末尾并在查询实际完成之前取消查询。

有没有办法做到这一点?

当前代码...

Protected Sub Button_Click(sender As Object, e As System.EventArgs) Handles Button.Click

    txtUsrID.Value = Session.Item("s_lngUsrID")
    txtUsrTypIDfk.Value = Session.Item("s_lngUsrTypIDfk")


    'Set up the command variables
    Dim Cnn As SqlConnection
    Dim Cmd As SqlCommand

    Cnn = New SqlConnection
    Cnn.ConnectionString = "TheString"
    Cmd = New SqlCommand
    Cmd.CommandType = Data.CommandType.StoredProcedure

    'Retrieve the record count
    Cmd.CommandText = "sptblTemp_GndrRprtPrGrp_Insrt"
    Cmd.Parameters.Add("@UsrIDfk", Data.SqlDbType.Int).Direction = Data.ParameterDirection.Input
    Cmd.Parameters("@UsrIDfk").Value = txtUsrID.Value

    Try
        Cnn.Open()
        Cmd.Connection = Cnn
        Cmd.CommandTimeout = 0
        Cmd.BeginExecuteNonQuery()


    Catch Excptn As Exception

        txtMssgs.Value = Excptn.Message

    End Try

    'clean up
    Cmd.Parameters.RemoveAt("@UsrIDfk")


    'close the connection if it's open
    If Cnn.State = Data.ConnectionState.Open Then
        Cnn.Close()
    End If
    Cmd.Dispose()
    Cnn.Dispose()

End Sub
asp.net vb.net azure-sql-database

评论

0赞 Nick Abbot 11/9/2023
执行查询的源代码语句是什么?
0赞 ProgrammerKyle 11/9/2023
我已经编辑了代码,但这是一个非常简单的“使用一个参数设置一个 SqlCommand,然后执行它”。
0赞 Craig 11/9/2023
你试过使用吗?ExecuteNonQueryAsync
0赞 Craig 11/9/2023
你是怎么尝试使用的?这应该可以正常工作(应该如此,使用不同的工作流程做同一件事的两种不同方法)。对于 ,请务必将命令和连接托管在外部作用域,以便在命令仍在运行时不会清理它们。在 / 工作流中,您不需要这样做,因为命令和连接将被状态机捕获。BeginExecuteNonQueryExecuteNonQueryAsyncBeginExecuteNonQueryAsyncAwait
0赞 ProgrammerKyle 11/9/2023
感谢 Craig 和 Nick Abbot,Nick 的建议让我顺利完成了大部分工作,但 Craig 关于在外部范围内托管连接和命令的评论促使我完成了最后一点。我现在似乎已经工作了。

答:

-1赞 Nick Abbot 11/9/2023 #1
  1. 将一个模块添加到您的 ASP 项目中,将其命名为 “公共模块”。
  2. 在该模块中,您将把代码和结果作为 Public、子例程和 Public 结果对象。
  3. 在按钮单击中,您可以检查 Result 对象是否为 什么都没有或空的。如果是,请创建一个线程来调用该子例程,该子例程执行 查询并填充 Public Result。第一次单击将创建线程/查询/结果。线程将继续 8分钟,然后做它的事情。

该公共结果对象将永远保留在该 IIS 进程中,直到该进程回收为止。

由于这需要 8 分钟,因此您可能需要设置一个变量来告知下一个用户/下一个单击查询正在进行中。

0赞 Craig 11/9/2023 #2

在所示代码中,问题在于承载执行的对象仅在本地过程作用域中,并且您正在关闭连接并在例程结束时释放连接和命令对象---在这种情况下,而不执行任何操作来等待查询完成。在它完成之前,您不希望在该作用域中调用它来保留它,因为它会阻塞并最终在功能上与您之前执行的操作相同。BeginExecuteNonQuerySqlCommandEndExecuteNonQuery

解决方案是确保 和 对象都托管在更高级别的范围内,以便您可以等待关闭和释放,直到查询完成执行。我会怀疑使用 a,因为它不会被实例化,因此多个用户之间可能存在冲突问题。某种实例可能更有意义。BeginExecuteNonQuerySqlCommandSqlConnectionModuleClass

您还可以将 / 工作流与 一起使用。这将需要较少的代码重构,因为编译器将生成类来为您保留幕后。为此,您可以添加到声明中,然后将该行更改为 .AsyncAwaitExecuteNonQueryAsyncSqlCommandAsyncSubCmd.BeginExecuteNonQueryAwait Cmd.ExecuteNonQueryAsync