Im работает с тем же правом в разных потоках, и я получаю optimisticlockexception
исключение. Я думаю, что в моем случае этого исключения следует избегать. Ситуация такова:
У меня есть класс A:
public class A{
List<B> b;
List<C> c;
public void addinListB(B elem){
b.add(elem);
}
public void addinListC(C elem){
c.add(elem);
}
}
Затем у меня есть класс SomeObject, который использует и модифицирует класс A. SomeObject:
public class SomeObject {
private static final Object lock = new Object();
public A search( String idA ){
synchronized (lock) {
A a = null;
try{
a = (A) getPersistenceContext()
.createQuery("from A where "+ id = :id ")
.setParameter("id", id).getSingleResult();
}catch (NoResultException e) {
A = new A();
getPersistenceContext().persist(bday);
getPersistenceContext().flush();
}
}
return a;
}
}
@Transactional
public someMethodB(){
A a = search(1);
B b = new B();
a.addBinListB(B);
}
@Transactional
public someMethodC(){
A a = search(1);
C c = new c();
a.addCinListC(c);
}
}
Таким образом, проблема в следующем: у нас есть 2 экрана, которые работают одновременно, один выполняет "someMethodB (1)", а другой выполняет "someMethodC (1)", ища тот же A id. Предположение: A для id = 1 не существует: это означает, что первый, выигравший блокировку, создаст экземпляр A, а другой будет использовать его. Из-за того, что один и тот же атакуемый obejct одновременно изменяется в обоих потоках. Таким образом, когда 1-й поток фиксирует транзакцию, выполняется сброс, но когда второй совершает ошибку, возникает optimisticlockexception
исключение.
Возможно ли исключить optimisticlockexception
исключение в этом случае? Я понимаю, что объект A "модифицирует" добавление двух разных объектов (B и C), но мы можем понять, что объект A является ОДНОМ объектом в базе данных, только оба потока добавляют новые объекты в разные таблицы, на которые указывают A.
Можно ли каким-либо образом одновременно модифицировать объект A (добавление к нескольким объектам B и C) и избежать исключения optimisticlockexception
?
С уважением
Каждый поток должен иметь свой собственный экземпляр entityManager, вы должны позволить контейнеру (если он есть) вставить экземпляр entityManager (@PersistenceContext) или сохранить выделенный экземпляр в ThreadLocal иначе
См. Как сделать доступ к БД с помощью Hibernate JPA потокобезопасным?
Существует не широко документированная опция Hibernate, в которой вы можете одновременно модифицировать ту же самую целостность, которая сохраняется, насколько вы не изменяете одни и те же поля. Конечно, это может конфликтовать с бизнес-семантикой, поэтому вы должны быть очень осторожны, если его принять. Поскольку вы изменяете разные коллекции внутри A, я предполагаю, что это соответствует вашему делу.
Optimistic-Lock = 'Dirty'
Как вы включили его? Ну, это не стандарт JPA, поэтому вам нужно использовать аннотацию hibernate @Entity и добавить атрибут optimisticLock = 'dirty'
См. Hibernate docs, redhat, а также эту ссылку, которая объясняет это (хотя она использует xml-конфигурацию, но эффект тот же)
Используйте на свой риск!