Метод E-D без учета состояния должен выполнять операцию чтения и вставки в транзакции. Первый шаг - сложная проверка, чтобы проверить, разрешена ли операция вставки с заданными параметрами.Условный метод блокировки EAN-объекта без состояния
public boolean DoCheckThanCreateAndAddItemToGroup(Item newItem, Group group) {
// STEP 1: checks if newItem can be created and added to group
// This is a complex operation with database reading and some logic
// using the current items of the group
if (!DoesNewItemFitInGroup(newItem, group)) {
return false;
}
// STEP 2: creates (persists) Item and adds it to Group
em.persist(newItem);
newItem.setGroup(group);
return true;
}
Очевидно, что весь метод должен быть заблокирован, чтобы предотвратить одновременное выполнение, чтобы не добавить два или более элементов, которые не помещаются вместе в группе. Обработка транзакций JTA по умолчанию не обеспечивает этого. Метод может выполняться параллельно с той же группой.
В настоящее время при параллельном запуске оба клиента могут пройти проверку до того, как любой из них выполнит операцию вставки, поэтому оба клиента вставляют свой новый элемент. Но эти элементы не подходят друг другу в группе: после того, как один добавлен, другой должен пропустить проверку и не должен быть добавлен.
Даже если я могу установить изоляцию транзакций на уровень SERIALIZABLE (но я не знаю, как это сделать), это не будет идеальным решением, потому что, когда метод работает одновременно с разными группами, блокировка бесполезна и замедляется вниз по системе без необходимости.
Другим решением было бы поместить метод в одноэлементный EJB с помощью @Lock (LockType.WRITE). Но проблема одна и та же: для разных блокировок групп нет необходимости.
Нечто подобное было бы решить эту проблему:
public boolean DoCheckThanCreateAndAddItemToGroup(Item newItem, Group group) {
lock(group) {
// STEP 1
// STEP 2
}
}
Как добиться такого поведения подходящим образом в среде EJB? (Возможно, в распределенной среде.)
Или любая другая идея, как правильно справиться с этой проблемой?
У вас есть возможность добавить уникальное ограничение на уровень БД, чтобы тот же самый новый элемент не был добавлен в ту же группу? Это обычное решение. –
Да, но это не обычный случай :-) Логика, которая может определить, может ли элемент быть добавлена в группу, намного сложнее. Это невозможно сделать на уровне БД. Это зависит от содержимого нового элемента, от содержания элементов, которые уже находятся в группе, и от некоторых других параметров группы. – GregTom
Является ли объект 'Group' (а не свойство' group' 'newItem') изменен, когда вы сохраняете' newItem'? Я думал о добавлении свойства version к свойству, так что, если Group change, второй параллельный запрос будет генерировать исключение (пессимистическая блокировка). –