JPA постоянство с использованием нескольких потоков - PullRequest
2 голосов
/ 29 июня 2011

У меня проблема при попытке сохранить объекты, используя несколько потоков .

Подробности:

Предположим, у меня есть объект PaymentOrder, у которого есть список PaymentGroup (отношение один ко многим), а PaymentGroup содержит список CreditTransfer (снова отношение один ко многим).

Поскольку число CreditTransfer огромно (в лаках), я сгруппировал его на основе PaymentGroup (основываясь на некоторой бизнес-логике) и создание потоков WORKER (по одному потоку для каждой группы платежей) для формирования объектов PaymentOrder и фиксации в базе данных.

Проблема в том, что каждый рабочий поток создает один из PaymentOrder (который содержит уникальный набор PaymentGroup с).

Первичный ключ для всех прав генерируется автоматически.

Итак, есть три таблицы: 1. PAYMENT_ORDER_MASTER, 2. PAYMENT_GROUPS, 3. CREDIT_TRANSFERS, все они сопоставлены отношением Один-ко-многим.

Из-за этого, когда второй поток пытается сохранить свою группу в базе данных, инфраструктура пытается сохранить тот же PaymentOrder, который был зафиксирован предыдущим потоком, транзакция завершается неудачей из-за некоторых других уникальных ограничений поля (контрольная сумма * 1031) *).

В идеале это должно быть 1..n..m (PaymentOrder -> PaymentGroup --> CreditTransfer`)

Что мне нужно сделать, это если в базе данных нет записи PaymentOrder, сделать запись, если она есть, не делать записи в PAYMENT_ORDER_MASTER, а только в PAYMENT_GROUPS и CREDIT_TRANSFERS.

Как я могу решить эту проблему, поддерживая логику split-master-payment-order-using-groups и несколько потоков?

Ответы [ 2 ]

2 голосов
/ 07 сентября 2011

У вас есть варианты.
1) Примитивно, но просто, поймайте ошибку нарушения ключа в конце и повторите попытку вставки без родителей.Предполагая, что ваши родители действительно уникальны, вы знаете, что другой поток только что родители ... продолжить с детьми.Это может плохо работать по сравнению с другими вариантами, но, возможно, вы получите нужную вам популярность.Если бы у вас был высокий процент родителей с одним ребенком, это бы сработало.

2) Измените уровень согласованности чтения.Это зависит от поставщика, но иногда вы можете прочитать незафиксированные транзакции.Это поможет вам увидеть работу других потоков перед фиксацией.Это не надежно, вы все равно должны сделать # 1, так как другой поток может проникнуть после чтения.Но это может улучшить вашу пропускную способность за счет большей сложности.Это может быть невозможным, на основе СУБД (или, может быть, это может случиться, но только на уровне БД, путаясь в других приложениях!)

3) Реализация рабочей очереди с однопоточным потребителем.Если основная дорогостоящая работа программы выполняется до уровня персистентности, ваши потоки могут «вставить» свои данные в рабочую очередь, где ключи не применяются.Затем вытащите один поток из рабочей очереди и сохраните его.Рабочая очередь может находиться в памяти, в другой таблице или в определенном поставщике месте (Weblogic Queue, Oracle AQ и т. Д.).Если основная работа программы перед сохранением, вы распараллеливаете ЭТО и возвращаетесь к одному потоку на вставках.Вы даже можете заставить своего потребителя работать в режиме «пакетной вставки».Sweeeeeeeet.

4) Расслабься.Кого волнует, если у одного и того же ребенка есть два родителя с одинаковой информацией?Я просто спрашиваю.Если вам позже не нужны супербыстрые обновления родительской информации, и вы можете изменить свои программы чтения, чтобы понять это, это может работать хорошо.Он не получит «A» в классе проектирования БД, но если это сработает .....

5) Реализовать глупую таблицу блокировок.Я ненавижу это решение, но оно работает - пусть ваш поток записывает, что он работает с родительским «x», и никто другой не может сделать это в качестве первой транзакции (и фиксации).Обычно приводит к той же самой проблеме (и другим - очистка записей позже, и т. Д.), Но может работать, когда вставки потомков выполняются медленно, а вставка в одну строку - быстро.У вас все еще будут столкновения, но меньше.

1 голос
/ 29 июня 2011

Hibernate-сессии не являются поточно-ориентированными. Соединения JDBC, лежащие в основе Hibernate, не являются поточно-ориентированными. Вместо этого рассмотрите возможность многопоточности вашей бизнес-логики, чтобы каждый поток использовал свой собственный сеанс Hibernate и соединение JDBC. Используя пул потоков, вы можете еще больше улучшить свой код, добавив возможность регулирования количества одновременных потоков.

...