如何在ASP中异步执行SQL事务.网网络服务

本文关键字:SQL 事务 网络服务 执行 异步 ASP | 更新日期: 2023-09-27 18:16:57

我有很多连接到它的webservice。我使用了以下代码:

IAsyncResult result = sqlCommand.BeginExecuteNonQuery();
while (!result.IsCompleted)
{
   System.Threading.Thread.Sleep(500);
}
sqlCommand.EndExecuteNonQuery(result);

我认为这不是一个最好的方法,因为我调用Sleep()。PS.这种方法会降低WebService和服务器的性能

更新2:我试着更多地描述我的代码:我有WebClient和2事件(ProgressChangedDownloadCompleted)

[WebMethod]
public void DonwloadFromRemoteServer(string uniqueId, string url)
{
    if (!Directory.Exists(uniqueId))
        Directory.CreateDirectory(uniqueId);
    WebClient wc = new WebClient();
    wc.DownloadProgressChanged += (sender, args) => wc_DownloadProgressChanged(sender, args, uniqueId, Path.GetFileName(url));
    wc.DownloadFileCompleted += (sender, args) => wc_DownloadFileCompleted(sender, args, uniqueId, Path.GetFileName(url));
    wc.DownloadFileAsync(new Uri(url), String.Format("{0}''{1}", uniqueId, Path.GetFileName(url)));
}
void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e, string uniqueId, string fileName)
{
    SqlConnection connection = new SqlConnection("Data Source=.''SQLSERVER;Initial Catalog=XRingtoneDB;Integrated Security=True;Asynchronous Processing=true");
    connection.Open();
    SqlCommand sqlCommand = new SqlCommand();
    sqlCommand.Connection = connection;
    sqlCommand.CommandText = String.Format("IF NOT EXISTS(SELECT uniqueId FROM downloads WHERE uniqueID = '{0}') " +
                                       "INSERT INTO downloads VALUES ('{0}', '{1}', '{2}') " +
                                       "IF EXISTS(SELECT uniqueId FROM downloads WHERE uniqueID = '{0}') " +
                                       "Update downloads " +
                                       "set progress='{2}' " +
                                       "where uniqueId='{0}' ", uniqueId, fileName, e.BytesReceived);
    AsyncCallback callback = ((result) =>
    {
        sqlCommand.EndExecuteNonQuery(result);
        connection.Close();
    });
    sqlCommand.BeginExecuteNonQuery(callback, sqlCommand);
}
void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e, string uniqueId, string fileName)
{
    SqlConnection connection = new SqlConnection("Data Source=.''SQLSERVER;Initial Catalog=XRingtoneDB;Integrated Security=True;Asynchronous Processing=true");
    connection.Open();
    SqlCommand sqlCommand = new SqlCommand();
    sqlCommand.Connection = connection;
    sqlCommand.CommandText = String.Format("update downloads " +
                                                "set progress='Completed' " +
                                                "where uniqueId='{0}' and fileName='{1}'", uniqueId, fileName);
    AsyncCallback callback = ((result) =>
    {
        sqlCommand.EndExecuteNonQuery(result);
        sqlCommand.Connection.Close();
    });
    sqlCommand.BeginExecuteNonQuery(callback, sqlCommand);
}

ProgressChanged工作正常,但DownloadCompleted只在调试模式下工作。我认为这是因为我需要在调用之间进行超时或等待。

Update3: 有时我有两个相同的行DB后执行下载!混淆我需要关闭所有的连接吗?

如何在ASP中异步执行SQL事务.网网络服务

你可以用AsyncCallback代替Sleep()

AsyncCallback callback = new AsyncCallback(HandleCallback);
sqlcommand.BeginExecuteNonQuery(callback, sqlcommand);

使用回调来处理异步状态。

private void HandleCallback(IAsyncResult result)
{
  SqlCommand command = (SqlCommand)result.AsyncState;
  command.EndExecuteNonQuery(result);
  ....
}

更新2

代码总体上是好的,但是,你允许多个文件下载在一个唯一的id ?如果你正在下载具有相同唯一Id的不同文件,它可以更新报告未完成进度的下载表。

不知道你的意思是DownloadCompleted只在调试模式下工作,但是你可以在你的WebMethod中使用一个私有变量来控制流。说到这一点,因为您使用DB来报告状态变化,但不插入大量数据,您应该考虑使用同步查询,以便它可以更好地存档结果。

你应该调用BeginExecuteNonQuery的重载,它接受一个回调,并在回调中结束查询。

如果您有额外的代码需要在数据库执行完成后执行,那么这些代码需要在回调中启动。

例如,如果您当前有:

sqlCommand.BeginExecuteNonQuery(callback, sqlCommand);
DoSomeAdditionalWorkNow();

DoSomeAdditionalWorkNow不会等到查询完成,如果它依赖于命令中更新的数据,您将遇到问题。

这可以通过将对额外工作方法的调用移动到回调中来补救:
AsyncCallback callback = ((result) =>
{
    sqlCommand.EndExecuteNonQuery(result);
    connection.Close();
    DoSomeAdditionalWorkNow();
});
sqlCommand.BeginExecuteNonQuery(callback, sqlCommand);
然而

我认为你的编程生活过于复杂了。您正在执行的查询不会长时间运行,您可以使用同步版本执行它们:

sqlCommand.ExecuteNonQuery();