Intershop ORMException не удалось обновить - обновите ORMObject
В кластерной межшопной среде мы видим много сообщений об ошибках. Я подозреваю, что связь между серверами приложений ненадежна.
Caused by: com.intershop.beehive.orm.capi.common.ORMException:
Could not UPDATE object: com.intershop.beehive.bts.internal.orderprocess.basket.BasketPO
Есть ли безопасный способ для локального сервера приложений, чтобы загрузить последний экземпляр.
BasketPO basket = null;
try{
BasketPOFactory factory = (BasketPOFactory) NamingMgr.getInstance().lookupFactory(BasketPOFactory.FACTORY_NAME);
try(ORMObjectCollection<BasketPO>baskets = factory.getObjectsBySQLWhere("uuid=?", new Object[]{basketID},CacheMode.NO_CACHING);){
if(null != baskets && !baskets.isEmpty()){
basket = baskets.stream().findFirst().get();
}
}
}
catch(Throwable t){
Logger.error(this, t.getMessage(),t);
}
Помогает ли метод ORMObject#refresh?
try{
if(null != basket)
basket.refresh();
}
catch(Throwable t){
Logger.error(this, t.getMessage(),t);
}
3 ответа
Вы получаете эту ошибку, потому что оптимистическая блокировка "терпит неудачу". Чтобы лучше понять проблему, я попытаюсь объяснить, как работает оптимистическая блокировка, в частности на уровне Intershop ORM.
В таблицах PO есть столбец с именем OCA (OCA == оптимистический атрибут управления?). Представьте, что два сервера (или два разных потока / транзакции) пытаются обновить одну и ту же строку в таблице. Из соображений производительности по умолчанию блокировка БД не задействована (например, с помощью команды select for update). Вместо этого первый поток / сервер увеличивает OCA на единицу, когда он успешно обновляет строку в своей транзакции.
Второй поток / сервер знает значение ОСА со времени, когда он создал свое собственное состояние. Затем он пытается обновить строку, выполнив аналогичный запрос:
UPDATE ... OCA = OCA + 1 ... WHERE UUID = <uuid> AND OCA = <old_oca>
Поскольку OCA уже увеличен первым потоком / сервером, это обновление завершается неудачно (на самом деле - обновляет 0 строк), и исключение, которое вы разместили выше, генерируется, когда уровень ORM обнаруживает, что ни одна строка не была обновлена.
Ваша проблема не в межсерверной связи, а в том, что либо:
- несколько серверов / потоков пытаются обновить один и тот же объект;
- в базе данных есть прямые обновления, которые обходят уровень ORM (менее вероятно);
Для решения этой проблемы вы можете:
- Избегайте этой ситуации вообще (очень рекомендую мной:-));
- Используйте блокировку ISH (очень громоздко);
- Используйте пессимистическую блокировку, поддерживаемую уровнем ISH ORM и Oracle (остерегайтесь потенциальных проблем с производительностью, взаимоблокировок, ошибок);
- Используйте блокировку Java - но поскольку серверы работают в разных JVM, это редко вариант;
OFFTOPIC замечания: я не уверен, почему вы используете getObjectsBySQLWhere
когда вы знаете первичный ключ (UUID). Насколько я помню ORMObjectCollection
-s должны быть закрыты, если не повторены полностью.
ОБНОВЛЕНИЕ: Если кластер не настроен правильно и многоадресные передачи не могут быть получены от узлов, вы не сможете решить проблемы программным путем.
"ORMObject.refresh()" помечает кэшированное общее состояние как недействительное. Следующий доступ к объекту перезагружает состояние из базы данных. Это влияет на производительность и увеличивает нагрузку на сервер базы данных.
НО: метод refresh () не перезагружает состояние экземпляра PO, если оно уже назначено текущей транзакции.
Было бы лучше, чтобы исследовать и исправить проблемы связи с сервером.
Другая возможность состоит в том, что это не проблема связи (многоадресная рассылка между узлами в кластере, я полагаю), а просто два запроса, пытающихся обновить корзину одновременно. Пример два ajax-запроса на обновление чего-либо в корзине.
Я бы не пытался "исправить" форму, это только принесло бы больше вреда, чем пользы. Скорее исследуйте дальше и отправьте назад больше информации.