我有一个监控目录更改的服务应用程序。
服务应用程序将密切监视目录。以下是它的作用:
它所做的一件事是它会将记录插入数据库。现在,由于多个线程可以同时运行,因此两个线程完全可能同时插入记录。
我想避免这种同时插入;相反,我希望这些插入排队,这意味着只有一个线程可以在一个时间点访问数据库。当其他区域已有1个访问数据库的线程时,其他服务无法访问数据库。
我想要的原因是因为在电涌激增的情况下,我只丢失了一笔交易,而不是很多交易。
我正在考虑使用锁定数据库事务的锁定语句。这是最好的方法吗?
P / S:我正在写一个与MySQL数据库对话的.Net服务。答案 0 :(得分:1)
我先看看你想要这样做的原因。通常应用程序就是这样运行的,2个客户端同时进行插入操作没有问题(除了代码中的错误方法之外)。
此外,解决方案也会因场景而异。一种选择是拥有一个Microsoft消息队列(MSMQ),并将插入移出这些服务,因此插入的负载由从队列中读取的进程控制。
更新1:我仍然不明白为什么你要避免插入并行运行(以及我在其他响应中读到的,我认为其他人做了)。我将引用你对此的两点评论:
我想要这个的原因是因为在电力浪涌的情况下,我只丢失了一笔交易,而不是很多交易。
另一个蚂蚁:
这是因为在插入之前,还有其他冗长的工作需要并行。只有在插入期间,才需要顺序访问。
如果我单独阅读第一篇文章,我实际上认为这是一个理由要求它们并行。您希望尽快完成它们。按顺序执行实际上会增加插入时间,因此有更多时间可以发生电源浪涌。
阅读第二篇,它让我觉得你可能更关心这些进程在并行上运行的效果,而插入没有进入数据库。这又意味着你希望尽快完成插入,所以没有理由按顺序完成。
对于内置支持,您可能有一个包含文件系统的分布式事务的情况(ms正在查看文件系统的事情,但我不记得他们是否曾在新的操作系统上做过某些事情) 。虽然分布式事务设置很麻烦(msdtc和对它使用的端口的访问)。
我遵循的一条好路径是向流程添加更多信息,以便能够分辨失败的位置。您甚至可能都没有编写自动恢复过程的代码,但至少您知道您将拥有确保知道出错的信息。
最简单的方法是在进程开始时插入一个标记,以便在完成时发出信号。如果它是一个长时间运行的过程,您可能希望获得更多类似于您不断更新的状态,以便能够告知它失败的步骤。另一种方法是将状态写入文件系统。
在任何情况下,它只会告诉您成功完成的最后一步,而不是当前步骤是否能够完成。这就是使重试逻辑变得更复杂的原因,因为你不能只在它停止的地方继续,你必须检查最后一步是否完成,这取决于每一步。
聚苯乙烯。如果是上述情况,很难从问题中分辨出来。您可能想要打开有关长时间运行的进程和/或自动重试的其他问题。
答案 1 :(得分:1)
数据库意味着允许多个进程同时插入数据,因此我无法看到您的问题。你有错误吗?
[编辑]你担心电力激增。哪里?在服务器或客户端?您可以选择以下选项:
服务器崩溃。让客户端检查“连接丢失”的错误代码,让他们重试插入,直到成功为止。要弄清楚这个错误代码,要么在插入过程中关闭服务器,要么拉出客户端的网络电缆(或者两者都有;有时候,出现意外网络问题时会出现不同的错误)。
客户端崩溃(更有可能的是,因为客户端通常是廉价的PC。如果用户可以访问它,它最终会被病毒感染,或者文件系统将被破坏,它将耗尽RAM,有人会安装一些“酷”的东西,它会摧毁一个重要的DLL,或者诸如此类的东西。在这种情况下,您必须再次启动客户端,检查已插入的内容(使用应用程序密钥)并从那里继续。
应用程序密钥是与您的业务流程相关的行的ID。例如,如果您销售卡片,则应用密钥可以是汽车的名称以及客户的名称加上时间戳。
答案 2 :(得分:0)
如果安装了多个Windows服务,并且有多线程Windows服务,那么您将获得多个同时插入。否则你不用担心。
答案 3 :(得分:0)
为什么每次插入都会创建一个新线程?为什么不简单地循环插入?只有在需要并行时才需要线程;在你的情况下,这似乎与你想要的完全相反。
[编辑]
这是因为在插入之前,还有其他冗长的工作需要并行。只有在插入期间,才需要顺序访问。
然后让那些线程向主线程报告,收集结果并将它们插入循环中。
答案 4 :(得分:0)
许多人之前说过:这是一件坏事。它将人工制造瓶颈。
但如果你真的想这样做,可以选择以下方法:
a)在表格上创建主键。无论如何,您应该这样做以实现干净的数据库设计。为了检查PK的有效性,数据库必须使用锁定,这将强制插入序列。
b)如果a)不足以达到您的目的,您应该使用单独的锁。根据您的环境,可能会有一个特殊的api(例如java concurrency api)。c)如果它不可用或您不喜欢它,您可以使用数据库的锁定机制:创建一个只包含一行的表。在每个插入上执行以下操作: - 阅读特殊表'for update'。这将(在大多数数据库设置中)保持任何其他会话不执行相同操作。 - 做插入。 - 提交。这将释放锁定并允许下一个会话继续。
并且提醒一下:这与正常尝试实现的完全相反:允许尽可能多的线程无干扰地工作
答案 5 :(得分:0)
我认为这里最好的选择是遵循Aaron的建议,并在处理完每个文件后回复线程;然后从单线程'manager'类更新数据库。
如果这不是一个选项,你可以在更新数据库的代码周围使用lock / synclock。
但是,您的一条评论说有多个服务正在运行。真的吗?多个Windows服务观看同一目录并进行多线程处理?为什么?我认为你必须更好地捍卫这种架构以获得更好的反应。