我以前使用过WCF服务,现在我有一个新项目。 我仍处于设计阶段,我想知道处理以下情况的最佳方法是什么。
我将让多个客户端同时连接到我的WCF服务,在服务上触发不同的方法(操作合同):
A。一些触发的方法只是纯粹的“读取”方法(例如GetListOfCustomers)。
B. 有些被解雇的方法是复杂的'Read'方法(例如GetAllProductsByCustomerId)。 这些方法需要从DB获取客户, 检查他的东西,然后得到他买的所有产品。 (意思是,在此方法中有2次调用数据库)。
C。有些是'写'方法(例如'RemoveCustomer'或'SetProductOutOfStock')。
我的问题是 - 如何同步所有这些调用,以免出现并发问题?
我不希望整个服务以串行方式处理呼叫,因为它会损害客户端的性能(某些呼叫可能需要3-4秒才能处理)。 那么我的解决方案是什么?
对具有“多个”线程的所有客户端使用“单个”实例,然后使用锁定对象?这不会导致串行吗?
或者我是否需要为'read'使用不同的锁定对象以及为'write'设置不同的锁定对象?
或者我是否需要锁定“写入”功能以及“读取”功能的其他内容?
这是我在StackOverflow上的第一个问题。 感谢任何可以提供帮助的人!
更新:我将使用'Linq-To-SQL'作为我的ORM。
答案 0 :(得分:2)
您不应该担心数据一致性问题,也不应该担心执行数据库查询时的并发性。如果我正确理解了您的情况,那么您需要确保的是,在执行一系列您希望“原子”的数据库查询时,您始终如一地使用事务。我将尝试在一个例子中解释它:
在这种情况下,您不希望发生的情况是,在1
的查询后返回 之前,更改了数据/ strong> 2
的所有查询都已完成。例如,如果同时删除其中一个客户,则更新相关数据毫无意义 - 这甚至可能导致一些错误。
所以你需要做的就是在BEGIN TRANSACTION
之前加1
之前加COMMIT
之后2
加{{1}}之类的东西。查找您正在使用的SQL方言的确切语法。
这基本上可以确保您使用的数据不会发生变化。事实上,它将被您的交易锁定;以及可能使用相同数据的所有其他查询都在等待您的事务完成。数据库智能地执行此类锁定,始终尝试锁定尽可能少的数据。
答案 1 :(得分:0)
你正在为网络设计,因此你需要拥抱并发,没有出路。在我看来,采取锁定并不是一种在网络上工作的好方法。 并发访问将会发生,您需要考虑如何处理并发错误而不是阻止并发问题。在Web上构建的任何并发控制机制使用有限且难以正确构建。
答案 2 :(得分:0)
我建议你阅读一些关于CQRS的内容,这是一种架构模式,可以解决你所面临的挑战。
作为适合您情况的示例解决方案,下图是一个可满足您要求的CQRS架构。
如果您想进一步解释,我很乐意提供。
<强>更新强>
主要原则是将数据库读写分开到不同的数据库中。
然后使用复制来确保您的读取数据库是最新的。
您还可以通过将两个数据库合并为一个和两个服务来实现上述体系结构。但是,您的原始问题是基于数据库使用模式存在冲突这一事实的数据库争用。
因此,这就是我提出CQRS作为解决方案的原因 - 数据库的写入端与读取端分离。读取侧可以针对选择进行优化(甚至可以针对访问速度进行去标准化)。
这意味着您将不会遇到与通过同一界面进行读写操作时相同的争用问题 - 这是您当前的方法。
此外,您不需要通过服务公开您的读取操作 - 简单的ADO会很好,服务端点只会引入延迟。
当您从读取模型读取时以及db编写服务更新数据模型时,您仍然可以使用linq2sql。
答案 3 :(得分:0)
我的问题是 - 如何同步所有这些调用,以便我不这样做 得到并发问题?
为什么你需要同步任何东西? DBMS可以很好地处理同步。当然,如果你知道你将有很多写入会因为锁而降低你的读取性能,那么你将不得不在体系结构层面上进行规划,但它没有太多做WCF。在那种情况下,正如休写的那样,CQRS 可能是一个合适的选择,尽管没有手头的规格很难说。
我不希望整个服务按顺序处理调用,因为它 会破坏客户端的性能(有些呼叫可能需要3-4次 要处理的秒数)。那么我的解决方案是什么?
然后使用PerCall实例化以及单个或多个并发(如果可以)。有关实例化/并发组合的详细信息,请查看here。
对具有“多个”线程的所有客户端使用“单个”实例 然后使用锁定对象?这不会导致串行吗?
单一实例会给你带来并发问题,请参阅我上面链接的文章。如果您需要Singleton服务,它将非常有用。
<强>更新强>
在回答你的评论时:恐怕我仍然不明白你希望在哪里遇到并发问题。如果您担心WCF服务,请避免使用单一实例:最可扩展的选项是PerCall / Multiple。
如果您问自己是否需要考虑CQRS,请随时阅读我在其他评论中链接的article by Udi Dahan。但请记住,CQRS需要花费一些时间来处理并增加您可能需要或可能不需要的项目的复杂性。
我建议不要无用地过度复杂化你的架构,对我来说,听起来像你的服务的实例化/并发性的正确配置就足够了。如果您不确定,请编写一些伪造系统预期负载的原型。更安全然后抱歉,特别是如果它将是一个长期存在的应用程序。