通过静态类从多个线程访问数据库

本文关键字:线程 访问 数据库 静态类 | 更新日期: 2023-09-27 18:35:14

我是一个自学成才的 C# 程序员,在对事物有非常透彻的理解方面,我在这里和那里错过了一些东西,现在我偶然发现了一些我无法在 SO 上找到答案的东西。我试图更好地了解 C# 中的线程安全性,但让我先指定上下文。

我目前正在开发一个Windows服务,该服务会关闭并根据驻留在SQL Server数据库中的计划执行一些监视工作。它将通过向许多"客户端服务器"发出http请求来监视某些服务器,安装在这些服务器上的客户端将使用请求的信息进行响应。

由于此监视器服务可能会变得非常繁忙,因此我已将其设置为在计划执行工作时将每个"计划指令"粘贴到新线程中。这是为了确保我的计时器保持良好的滴答声,准备好向下一个"客户端服务器"触发下一条指令。

每条指令的一部分是必须登录它已成功执行的数据库以及响应是什么等等。现在我的监视器服务中有一个public static class Logger,我相信这很方便,因为我现在可以轻松地以这种方式调用它,Logger.Log(... )每当我需要记录事情时。此日志记录在此类中通过 EF 发生到 SQL Server 数据库中。

对我来说,这一切听起来真的很酷,我对它的工作原理非常满意,但我还没有进行任何负载测试。我对所有这些的问题是,我的大脑告诉我,由于我的记录器类是静态的 - 根据我的理解,因此它只实例化一次?- 如果同时尝试调用Logger.Log(.. )的线程不止 1 个,我的监视器服务将发生不好的事情。

这里有人可以启发我吗?我的想法是对还是错?如果你知道答案,请解释清楚,因为我很想理解它。:)

更新:

感谢您到目前为止的回复,事情变得越来越清晰,因为人们正在询问有关Log方法的更多详细信息,而我目前不在开发PC上,我将尝试更详细地解释它的工作方式。

Log方法所做的只是根据以前实例化的一些对象中的数据(作为参数传入该方法)通过 EF 将记录添加到 SQL 数据库。数据库上下文实例化为静态类上的静态私有变量。这样做的原因是,我不必继续在重载中放置 using 语句。

通过静态类从多个线程访问数据库

每个方法,无论是静态的还是虚拟的,都有自己的框架,因此不涉及线程问题。问题出现在方法实现中:一些静态方法将使用静态变量或静态资源,它们都是同一个管道,你会遇到竞争条件。但是在静态方法中声明的局部变量不是静态的,所以如果你的方法不修改静态变量或资源,你会没事的。

您的Logger类的文档在线程安全方面有什么说明?静态类或方法本身并没有什么线程不安全的。

如果调用的方法或属性,无论它是否是静态的

  • 引用相关方法的本地可验证对象(例如,不引用任何实例或静态成员),以及
  • 创建需要与之协作的任何其他类的自己的实例

您应该是线程安全的。请注意,在其他类中调用的任何方法或属性也必须同样是线程安全的。

static为危险代码提供了机会,但它不能保证这一点。 如果您使用的是static类/方法,则必须注意不要使用任何实例数据。

这对您来说意味着什么? 基本上,您希望在 Log 方法中实例化DbContext,执行日志记录并Dispose DbContext(将用法包装在 using 语句中)。 只要不共享实例数据,您就会没事。

但是,如果您在静态构造函数中执行某些操作或使用类级变量,则可能会产生问题。

编辑:在特定情况下,您不应该在所有线程之间共享DbContext。 请在此处讨论DbContext的正确范围。 它应该在每个方法中实例化。

此博客条目陈述以下内容(并提供说明):

[这些考虑]中的大多数都倾向于指向一个不共享的短暂上下文。

这就是我推荐的经验法则。