Как мне решить проблемы с параллелизмом INSERT, я использую eclipselink jpa и mysql со glassfish 4.1? - PullRequest
0 голосов
/ 01 мая 2019

В мое приложение входит 2 транзакции, которые хотят обновить подмножество тех же объектов.Однако некоторые из этих сущностей отсутствуют в базе данных, поэтому оба потока создают одну и ту же сущность и пытаются ее зафиксировать.Вызов базы данных. Дублирующая запись для первичного ключа.Как мне справиться с этим?

например, Транзакция 1 хочет обновить сущности A, B, C, D, E, F Транзакция 2 хочет обновить сущности D, E, F, G, H, I Моя база данных толькоимеет записи для сущностей A, C, E, G и I

Так что транзакции 1 и 2 пытаются создать сущность D. В которой второй поток не может зафиксировать, поскольку D является первичным ключом и теперь уже существует.

Я пытался использовать pessimistic_write, но это не помогает записям, которые еще не существуют.

Я попытался обернуть мой вызов persist () в попытку catch, но похоже, чтоИсключение выдается внутренне в JPA, и мое приложение его никогда не видит.

Большинство поисков в Google возвращают примеры блокировки существующих записей, и если в них упоминаются одновременные вставки, это выходит за рамки статьи.

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

Я думал опредварительно заполняет базу данных, но, вероятно, существует более миллиарда возможных действительных ключей сущностей, хотя я работаю только с набором из примерно 20 000 ключей, но я не знаю, что это такое, пока не произойдет транзакция.

Это мой персистентный код с упаковкой try catch, я никогда не вижу сообщения «INSERT Persistence collision», выходящего из моего приложения, только трассировка стека JPA.

if (cellmu == null)
{
    CellMUEntity cellmuNew = new CellMUEntity();
    cellmuNew.setId(cellOuter);
    cellmuNew.setDistribution(mus);
    try {
        em.persist(cellmuNew);
    } catch (Exception e) {
        System.out.println("INSERT Persistence collision, " +e.getClass().getName() +" read and refine (" + cellOuter+")" );
        cellmuNew = em.find(CellMUEntity.class,cellOuter,LockModeType.PESSIMISTIC_WRITE);
        cellmuNew.setDistribution(cellmuNew.getDistribution().refine(mus));
        em.merge(cellmuNew);
    }
}

здесь есть часть трассировки стекаиз jpa ...

[2019-05-01T21:07:07.654+1000] [glassfish 4.1] [WARNING] [jts.unexpected_error_occurred_in_after_completion] [javax.enterprise.system.core.transaction.com.sun.jts.jta] [tid: _ThreadID=70 _ThreadName=p: thread-pool-1; w: 2] [timeMillis: 1556708827654] [levelValue: 900] [[
  JTS5054: Unexpected error occurred in after completion
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150605-31e8258): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '6ad63bd4' for key 'PRIMARY'
Error Code: 1062
Call: INSERT INTO mucell (cellid, mu_high, mu_low) VALUES (?, ?, ?)
    bind => [3 parameters bound]
Query: InsertObjectQuery((face=3, pos=ad63bd400000000, level=13):[0.0, 47499.492305012])
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
...