2011-06-28 109 views
1

我尝试使用多线程来尝试持久化对象时遇到问题。使用多线程的JPA持久性

详情:

假设我有其中有PaymentGroup列表(一对多的关系)和PaymentGroup(再次一对多的关系)包含CreditTransfer列表的对象PaymentOrder

由于CreditTransfer数量巨大(以万卢比),我已经根据PaymentGroup(基于一些业务逻辑) 和创建WORKER线程(一个线程每个PaymentGroup)形成PaymentOrder对象和分组它在数据库中提交。

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

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

因此有三个表格,1.PAYMENT_ORDER_MASTER,2.PAYMENT_GROUPS,3.CREDIT_TRANSFERS,全部由一对多关系映射。

因为,当第二线程试图坚持其组中的数据库,该框架试图坚持同一PaymentOrder,其前一个线程提交,交易失败由于一些其他唯一字段约束(的PaymentOrder的校验和)。

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

我需要实现的是如果在数据库中没有的PaymentOrder记项,表项时,它的存在,请勿在PAYMENT_ORDER_MASTER中输入,但只能在PAYMENT_GROUPSCREDIT_TRANSFERS之间输入。

我该如何克服这个问题,维护split-master-payment-order-using-groups逻辑和多线程?

回答

2

你有选择。
1)原始但简单,最后抓住关键违规错误,并重试你的插入没有父母。假设你的父母是真正独一无二的,你知道另一个线索就是父母......继续与孩子们接触。与其他选项相比,这可能表现不佳,但也许你会得到所需的流行音乐。如果你的父母和一个孩子的比例很高,那么它会很好地工作。

2)改变你的阅读一致性水平。它是特定于供应商的,但您有时可以阅读未提交的交易。这将有助于您在提交之前看到其他线程的工作。这不是万无一失的,你还必须执行#1,因为另一个线程可以在读取后潜入。但它可能会提高吞吐量,但代价是更复杂。根据RDBMS(或者它可能发生,但仅在数据库级别,搞乱了其他应用程序!)

3)使用单线程使用者实现工作队列。如果程序的主要昂贵工作在持久层级之前,那么可以让你的线程将他们的数据“插入”到一个工作队列中,在这里工作队列没有强制执行。然后让单个线程从工作队列中拉出并保留。工作队列可以在内存中,另一个表中或供应商特定位置(Weblogic队列,Oracle AQ等)中。如果程序的主要工作在持久化之前,则将THAT并行化并返回到插入的单个线程。您甚至可以让您的客户以“批量插入”模式工作。 Sweeeeeeeet。

4)放松你的约束。如果同一个孩子有两个父母持有相同的信息,谁真的关心?我只是问问。如果您以后不需要父级信息的超级快速更新,并且您可以更改您的阅读程序以了解它,则它可以很好地工作。它不会让你在数据库设计类“A”,但如果它的工作.....

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

0

休眠会话不是线程安全的。底层Hibernate的JDBC连接不是线程安全的。考虑多线程处理业务逻辑,以便每个线程都可以使用它自己的Hibernate会话和JDBC连接。通过使用线程池,您可以通过添加限制并发线程数量的能力来进一步改进代码。