一尘不染

使用多个线程的JPA持久性

hibernate

我尝试使用 多个线程 持久化对象时遇到问题。

细节 :

假设我有一个对象PaymentOrder,该对象具有PaymentGroup(一对多关系)PaymentGroup列表,并且又包含(一对多关系)列表CreditTransfer

由于数量CreditTransfer庞大(以十万计),我基于PaymentGroup(基于某些业务逻辑)将其分组,并创建了 WORKER
线程(每个PaymentGroup一个线程)以形成PaymentOrder对象并提交到数据库中。

问题是,每个工作线程都创建一个PaymentOrder(包含唯一的一组PaymentGroup)。

所有实体的主键都是自动生成的。

因此,存在三个表,即1.
PAYMENT_ORDER_MASTER,2。PAYMENT_GROUPS,3。CREDIT_TRANSFERS,它们都通过一对多关系进行映射。

因此,当第二个线程尝试将其组持久存储在数据库中时,框架将尝试持久化与PaymentOrder上一个线程提交的组相同的事务,由于其他一些唯一字段约束(的校验和PaymentOrder),导致事务失败。

理想情况下,它必须为1..n..m(PaymentOrder-> PaymentGroup -->CreditTransfer`)

我需要实现的是,如果PaymentOrder数据库中没有条目,则创建一个条目;如果数据库中没有条目,则不要在中创建条目PAYMENT_ORDER_MASTER,而仅在PAYMENT_GROUPS和中创建条目CREDIT_TRANSFERS

我如何解决这个问题,同时维护拆分主付款顺序使用组逻辑和多个线程?


阅读 315

收藏
2020-06-20

共1个答案

一尘不染

你有选择。
1)原始但简单,最后捕获密钥冲突错误,然后在没有父母的情况下重试插入。假设您的父母确实是独一无二的,您就会知道父母刚刚采取了另一种措施……带着孩子。与其他选项相比,这可能效果不佳,但也许您会得到所需的流行音乐。如果您的父母中有一个孩子的父母百分比很高,则效果很好。

2)更改您的读取一致性级别。它是特定于供应商的,但是您有时可以读取未提交的事务。这将有助于您在提交之前查看其他线程的工作。它不是万无一失的,您仍然必须执行#1,因为读取后另一个线程可能会潜入。但这可能会提高吞吐量,但会增加复杂性。基于RDBMS可能是不可能的(或者可能会发生,但只能在数据库级别上,弄乱其他应用程序!)

3)用单线程使用者实现工作队列。如果程序的主要昂贵工作在持久性级别之前,则可以让线程将其数据“插入”到工作队列中,在其中不执行键。然后从工作队列中拉出一个线程并继续执行。工作队列可以在内存中,在另一个表中或在供应商特定的位置(Weblogic
Queue,Oracle
AQ等)。如果程序的主要工作在持久性之前,则对THAT进行并行处理,然后返回到插入上的单个线程。您甚至可以使消费者在“批量插入”模式下工作。Sweeeeeeeet。

4)放松约束。谁真正在乎同一个孩子是否有两个父母持有相同的信息?我只是问问。如果以后您不需要父信​​息的超快速更新,并且可以更改阅读程序以了解它,那么它可以很好地工作。在数据库设计课程中,它不会使您获得“
A”,但如果可以的话…

5)实现一个愚蠢的锁表。我讨厌这个解决方案,但是它确实有效—让您的线程写下它正在父级“
x”上工作,并且没有其他人可以作为它的第一个事务(和提交)。通常会导致相同的问题(以及其他问题–稍后清除记录等),但是在子插入速度较慢而单行插入速度较快时也可以使用。您仍然会有碰撞,但是碰撞更少。

2020-06-20