Отсутствует поле в заявлении об обновлении в eclipselink - PullRequest
0 голосов
/ 04 августа 2020

Я использую payare 5.201, который использует eclipselink 2.7.

Я использую EJB (компоненты без сохранения состояния) для обработки своих транзакций.

Есть класс A и метод X, который извлекает объект E из базы данных и вызывает метод Y в классе B и передает E в качестве параметра.

Метод X является @ASynchronous, что означает, что он будет выполняться в отдельном потоке.

Итак, метод AX выполняется в потоке T1 и BY в T2.

Когда AX вызывает BY, AX не должен ждать, потому что BY возвращает асинхронно.

Непосредственно перед тем, как AZ вызывает BY, он устанавливает значение F в значение true в E Это индикатор того, что BY работает.

AX передает E, что кажется странным. Это сделано, чтобы быть уверенным, что BY получит правильный объект.

Если бы я, например, передал идентификатор E и запросил его в BY, я мог бы получить условия гонки, потому что это не гарантируется, когда E фиксируется в T1 поэтому BY может получить старое значение EF

Когда BY получает E, тогда это тот же объект, но он не зарегистрирован в (другом) entitymanager в B. Когда BY готов, тогда E объединяется с entitymanager, который эффективно обновляет любые изменения, внесенные в E.

Когда BY готов, EF устанавливается в false, чтобы указать, что это сделано.

Когда BY выходит, EJB берет на себя и обновляет значения в E в базу данных.

Проблема, которую я вижу сейчас, заключается в том, что EF не обновляется. В журналах sql я вижу, что запись обновлена, но поля F нет в операторе обновления. Это будет означать, что eclipselink не видит никаких изменений для этого поля. Самое забавное, что это случается не всегда.

После исследования затмения я прочитал об отслеживании изменений, которое можно использовать, когда включено ткачество. Это можно, например, активировать с помощью @ChangeTracking (ChangeTrackingType.ATTRIBUTE) в сущности.

Я использую Payara, и плетение включено по умолчанию, и у меня нет аннотаций @ChangeTracking, что означает, что eclipselink будет выберите их во время выполнения на основе некоторых правил.

Когда я устанавливаю

@ChangeTracking(ChangeTrackingType.ATTRIBUTE)

в сущности E, проблема исчезает и EF обновляется.

Сущность E имеет некоторые отношения с нетерпеливым fetchtype. Когда я устанавливаю тип выборки этих отношений на LAZY, он также снова работает. Я предполагаю, что это произошло из-за того, что у меня был активный тип fetchtype.

Вопросы:

  • Почему эта проблема возникает только иногда?
    • Я бы ожидал, что ChangeTrackingType будет определен один раз?
  • Как я могу во время выполнения «спросить» систему, какой ChangeTrackingType используется для таблицы.
    • , чтобы я мог проверить другое значение ChangeTrackingType
  • Существуют ли настройки отладки, в которых я могу позволить eclipselink регистрировать значения ChangeTrackingType для каждой таблицы?

1 Ответ

0 голосов
/ 07 августа 2020

Благодаря @Chris я смог подтвердить, что ObjectChangePolicy для моего класса сущностей действительно ОТЛОЖЕН.

Это значение означает ( ChangeTracking ), что обновление sql для поля будет выполняться только тогда, когда значения отличаются от значения при загрузке из базы данных.

Существует также параметр ATTRIBUTE.

Это обновит поле при вызове установщика и исходное значение отличается.

Так вот, что на самом деле происходит и вызывает проблему:

ОТЛОЖЕННЫЙ процесс:

Когда BY загружает E-запись до того, как AX смог зафиксировать, тогда в Поле BY F по-прежнему будет ложным. Если затем AX фиксируется, тогда F истинно в базе данных.

Когда BY завершится, в конце он установит F в false. Но когда E был загружен, значение также было false, что означает, что обновление не будет.

Теперь о решении:

Во-первых, возможно (хотя и маловероятно), что BY является выполняется быстрее, чем AX. Чтобы покрыть это, BY должен сказать AX, что F не должен устанавливать значение true. Этого легко добиться, установив для F значение false в E, которое передается в качестве параметра.

Для второй части есть два известных мне решения:

1)

В конце BY принудительно обновите, используя EntityManager.flush(), и сразу после этого обновите sh данные, используя EntityManager.refresh(), а после этого снова установите F в false. Обновление данных гарантирует, что F теперь истинно, и обновит его после того, как F будет установлено в false.

2)

Используйте ATTRIBUTE и сначала установите значение true, затем false. Звучит действительно глупо, но это простой способ заставить систему обновить поле.

Ясно, что я предпочитаю вариант 2, поскольку первый вариант требует перезагрузки объекта и его повторного обновления, что вызывает 2 дополнительных sql заявления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...