当我尝试使用持久化对象时遇到问题多线程.
细节 :
假设我有一个对象PaymentOrder
其中有一个列表PaymentGroup
(一对多关系)和PaymentGroup
包含一个列表CreditTransfer
(再次是一对多关系)。
由于数量CreditTransfer
是巨大的(十万),我根据PaymentGroup
(基于一些业务逻辑)
并创造WORKER线程(每个 PaymentGroup 一个线程)形成PaymentOrder
对象并提交到数据库中。
问题是,每个工作线程都创建一个PaymentOrder
(其中包含一组独特的PaymentGroup
s).
所有实体的主键都是自动生成的。
所以有三个表,1. PAYMENT_ORDER_MASTER,2. PAYMENT_GROUPS,3. CREDIT_TRANSFERS,都是通过一对多关系映射的。
因此,当第二个线程尝试将其组保留在数据库中时,框架会尝试保留相同的组PaymentOrder
,前一个线程提交了,由于一些其他唯一字段约束(校验和),事务失败PaymentOrder
).
理想情况下它必须是 1..n..m (PaymentOrder
->支付组-->
学分转移`)
我需要实现的是如果没有条目PaymentOrder
在数据库中输入一个条目,如果存在,则不要输入PAYMENT_ORDER_MASTER
,但仅在PAYMENT_GROUPS
and CREDIT_TRANSFERS
.
如何克服这个问题,维护 split-master- payment-order-using-groups 逻辑和多线程?
你有选择。
1)原始但简单,在最后捕获关键违规错误并在没有父母的情况下重试插入。假设你的父母确实是独一无二的,你知道另一个线程只是让父母……继续照顾孩子。与其他选项相比,这可能表现不佳,但也许您会得到所需的流行。如果您有一个孩子的父母比例较高,那么效果会很好。
2) 更改读取一致性级别。它是特定于供应商的,但有时您可以读取未提交的事务。这将帮助您在提交之前查看其他线程的工作。这并不是万无一失的,你仍然必须执行#1,因为另一个线程可以在读取后潜入。但它可能会提高您的吞吐量,但代价是更加复杂。基于 RDBMS 可能是不可能的(或者也许它可能发生,但仅限于数据库级别,弄乱其他应用程序!)
3) 使用单线程消费者实现工作队列。如果程序的主要昂贵工作是在持久性级别之前,您可以让线程将其数据“插入”到工作队列中,其中不强制执行键。然后从工作队列中提取一个线程并保留。工作队列可以位于内存中、另一个表中或供应商特定的位置(Weblogic 队列、Oracle AQ 等)。如果程序的主要工作是在持久化之前,那么您可以并行化它并返回到插入上的单个线程。您甚至可以让您的消费者在“批量插入”模式下工作。亲爱的。
4)放松你的限制。谁真正关心同一个孩子的两个父母是否持有相同的信息?我只是问问。如果您以后不需要对家长信息进行超快速更新,并且可以更改阅读程序来理解它,那么它可以很好地工作。它不会让你在数据库设计课上获得“A”,但如果它有效......
5) 实现一个愚蠢的锁表。我讨厌这个解决方案,但它确实有效——让你的线程写下它正在父“x”上工作,而其他人不能,因为它是第一个事务(和提交)。通常会导致相同的问题(以及其他问题 - 稍后清理记录等),但在子插入速度慢而单行插入速度快时可以工作。仍然会发生碰撞,但会减少。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)