使用多个线程的JPA持久性

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

细节 :

假设我有一个对象PaymentOrder ,它有一个PaymentGroup列表(一对多关系), PaymentGroup包含一个CreditTransfer列表(一对多关系)。

由于CreditTransfer的数量巨大(以CreditTransfer ),我根据PaymentGroup (基于某些业务逻辑)对其进行分组,并创建WORKER线程(每个PaymentGroup一个线程)以形成PaymentOrder对象并在数据库中提交。

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

所有权利的主键都是自动生成的。

所以有三个表,1。PAYMENT_ORDER_MASTER,2。PAYMENT_GROUPS,3。CREDIT_TRANSFERS,都是由One to Many关系映射的。

因此,当第二个线程试图将其组保留在数据库中时,框架会尝试持久保存相同的PaymentOrder ,前一个线程已提交,由于某些其他唯一字段约束( PaymentOrder的校验和),事务将失败。

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

我需要实现的是,如果在数据库中没有PaymentOrder的条目进行输入,如果它在那里,不要在PAYMENT_ORDER_MASTER输入,而只在PAYMENT_GROUPSCREDIT_TRANSFERS

我怎样才能解决这个问题,维护split-master-payment-order-using-groups逻辑和多个线程?

你有选择。
1)原始但很简单,在最后捕获密钥违规错误并在没有父母的情况下重试插入。 假设你的父母是真正独特的,你知道另一个线索只是做了父母……继续孩子。 与其他选项相比,这可能表现不佳,但也许您可以获得所需的弹出窗口。 如果你有一个孩子的父母有很高的百分比,它会很好地工作。

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

3)使用单线程使用者实现工作队列。 如果程序的主要昂贵工作在持久性级别之前,则可以让您的线程将其数据“插入”到不强制执行密钥的工作队列中。 然后从工作队列中拉出一个线程并保持不变。 工作队列可以位于内存中,另一个表中,也可以位于特定于供应商的位置(Weblogic队列,Oracle AQ等)。 如果程序的主要工作在持久性之前,那么您可以并行化THAT并返回插入的单个线程。 您甚至可以让您的消费者以“批量插入”模式工作。 Sweeeeeeeet。

4)放松你的约束。 如果同一个孩子有两个父母持有相同信息,谁真正关心? 我只是问问。 如果您以后不需要父信​​息的超快速更新,并且您可以更改您的阅读程序以理解它,它可以很好地工作。 它不会让你在DB设计课上成为“A”,但如果它有效……

5)实现一个傻瓜锁表。 我讨厌这个解决方案,但它确实有效 – 让你的线程记下它正在处理父“x”而没有其他人可以作为它的第一个事务(和提交)。 通常会导致相同的问题(以及其他问题 – 稍后清理记录等),但是当子插入缓慢且单行插入速度很快时可以工作。 你仍然会发生碰撞,但会更少。

Hibernate会话不是线程安全的。 支持Hibernate的JDBC连接不是线程安全的。 考虑multithreading化您的业务逻辑,以便每个线程都使用它自己的Hibernate会话和JDBC连接。 通过使用线程池,您可以通过添加限制同时线程数量的function来进一步改进代码。