3

我有一个 Windows 服务,它通过 RabbitMQ 接收消息,这会触发一个事件处理程序,它会做一些工作,然后尝试将结果保存到数据库中。它使用以下线程:

ThreadPool.QueueUserWorkItem(ProcessMessageOnThread, messageReceived);

whereProcessMessageOnThread是一个执行工作的方法,messageReceived它是从 RabbitMQ 出列的消息的表示。

正常情况下windows服务按预期运行,即dequeue、process和persist。

我想确保我的所有消息都得到处理并给予公平的更改以进行处理,所以如果我无法打开与 SQL Server 的连接,我只需将消息重新排队以再次处理它(希望那个时候 SQL Server 会回来,否则这将继续 - 我很好)。

现在问题来了,当进程按预期运行一段时间后,SQL Server 连接池已满,然后SQL Server 断开连接,现在情况变得有点不稳定。

可能会发生以下两种情况之一:

  • 抛出一个异常connection.Open()- 但是我抓住了这个,所以不担心它

  • 引发异常cmd.ExecuteNonQuery()- 这是我正在执行存储过程的地方

这是我需要弄清楚如何处理的第二个选项。以前我认为这里的任何异常都意味着我传递给存储过程的数据存在问题,因此应该将其移出队列并让其他东西对其进行分析。

但是,现在我认为我需要一种新方法来处理异常与实际未建立的连接有关的情况。

我查看了SqlException该类并注意到一个名为的属性Class,它有这个描述Gets the severity level of the error returned from SQL Server,现在关于这个的信息说:

严重级别为 10 或更低的消息是信息性的,表示由用户输入的信息错误引起的问题。从 11 到 16 的严重级别由用户生成,并且可以由用户进行更正。从 17 到 25 的严重级别表示软件或硬件错误。当发生 17、18 或 19 级错误时,您可以继续工作,尽管您可能无法执行特定语句。

这是否意味着修复我的异常处理,我可以检查if (ex.Class > 16)然后重新排队消息,因为问题在于连接else将其丢弃,因为它很可能与发送到存储过程的格式错误的数据有关?

cmd.ExecuteNonQuery()所以问题是,我应该如何进行异常处理,如果抛出的异常是由于断开的连接,我该如何检测调用时。


更新:

我以前遇到过连接没有返回到池中的问题(这是由于线程问题)并且已经解决了这些问题,所以我相信这个问题与没有返回到池中的连接无关。此外,围绕连接的用途的逻辑非常简单,我也确保它们始终关闭......所以我对与 Sql Server 断开连接然后捕获行为有关的答案更感兴趣cmd.ExecuteNonQuery()

4

1 回答 1

3

由于各种原因,连接池中的连接可能会进入奇怪的状态,所有这些都与糟糕的应用程序设计有关:

  • 在关联的数据读取器之前关闭连接
  • 更改池不重置的设置(如事务隔离级别)
  • 启动异步查询 ( BeginOpenReader),然后在异步处理程序触发之前将连接返回到池

您应该调查您的应用程序并确保连接正确返回到池中。有助于调试的一件事是在开发环境中减小应用程序池的大小。您在连接字符串中更改池的大小:

...;Integrated Security=SSPI;Max Pool Size=2;Pooling=True;

这使得池化问题很容易重现。

如果找不到原因,但仍需要部署修复程序,则可以使用ClearPool或之一ClearAllPools。这样做的好地方是当您在Open()或之后检测到可疑异常之一时ExecuteNonQuery()。两者都是SqlConnection类的静态方法:

SqlConnection.ClearPool(yourConnection);

或者更粗略的方法:

SqlConnection.ClearAllPools()

请注意,这基本上是Pokémon 异常处理。如果它有效,您将不知道为什么。:)

于 2012-09-24T16:19:34.000 回答