2016-05-20 4 views
3

Я знаю, что есть некоторые вопросы по этому вопросу уже, но я думаю, что это другое.JPA Version Entity merge

Скажем, у меня есть этот класс:

@Entity 
public class foo{ 
    @Id 
    @GeneratedValue 
    private long id; 

    @Version 
    private long version; 

    private String description; 
    ... 
} 

Они создать некоторые объекты и сохраняются их к БД с помощью JPA добавить().

Позже я получаю все из репозитория, используя JPA all(); Из этого списка я выбираю один объект и изменяю описание.

Затем я хочу обновить этот объект в репозитории, используя JPA merge() (см. Код).

Проблема в том, что она работает в первый раз, когда я пытаюсь изменить описание (значение версии теперь 2). Во второй раз возникает оптимистическое исключение Exclusive, говорящее, что этот объект был изменен тем временем.

Я использую H2, имеет БД во встроенном режиме.

MERGE КОД:

//First: persist is tried, if the object already exists, an exception is raised and then this code is executed 
try { 
    tx = em.getTransaction(); 
    tx.begin(); 
    entity = em.merge(entity); 
    tx.commit(); 
    } catch (PersistenceException pex) { 
       //Do stuff 
      } 

Что может быть не так, где?

спасибо.

РЕДАКТИРОВАТЬ (больше кода)

// Foo б получают путем получать все объекты из БД с помощью JPA все(), а затем один объект, выбранный из этого списка

b.changeDescription (» Что-то новое!");

// метод обновления вызовов (Merge код уже отвечал)

+0

вы пробовали em.persist вместо слияния? Метод слияния отслеживает объект после обновления. В зависимости от вашей конфигурации возможно, что обновление уже отправлено в БД. – fhofmann

+0

Опубликовать еще код. Релевантно, как вы загружаете и модифицируете объект и как вы вызываете код, который вы опубликовали. –

+0

@AlanHay Я отредактировал исходное сообщение с еще одним кодом, который представляет мою ситуацию. –

ответ

0

Here are пост, который объясняет прекрасно, когда OptimisticLockException отбрасывается.

Кроме того, для дальнейшего использования вы можете заставить JPA избегать этой проверки объектов в памяти при обновлении, но вы хотите изменить ее на стороне БД только в конце этой транзакции, используя метод «отделить» на EntityManager:

em.detach(employee); 
1

Я бы предположил, что вы меняете элементы в списке от разных клиентов или разных потоков. Вот что вызывает OptimisticLockException.

Один поток, в его собственном EntityManager, читает объект Foo и получает во время чтения @Version.

// select and update AnyEntity 
EntityManager em1 = emf.createEntityManager(); 
EntityTransaction tx1 = em1.getTransaction(); 
tx1.begin(); 
AnyEntity firstEntity = em1.createQuery("select a from AnyEntity a", AnyEntity.class).getSingleResult(); 
firstEntity.setName("name1"); 
em1.merge(firstEntity); 

Другой клиент считывает и обновляет Foo объекта в то же время, до того, как первый клиент совершил свои изменения в базу данных:

// select and update AnyEntity from a different EntityManager from a different thread or client 
EntityManager em2 = emf.createEntityManager(); 
EntityTransaction tx2 = em2.getTransaction(); 
tx2.begin(); 
AnyEntity secondEntity = em2.createQuery("select a from AnyEntity a", AnyEntity.class).getSingleResult(); 
secondEntity.setName("name2"); 
em2.merge(secondEntity); 

Теперь первый клиент совершает свои изменения в базу данных:

// commit first change while second change still pending 
tx1.commit(); 
em1.close(); 

И второй клиент получает OptimisticLockException, когда он обновляет свои изменения:

// OptimisticLockException thrown here means that a change happened while AnyEntity was still "checked out" 
try { 
    tx2.commit(); 
    em2.close(); 
} catch (RollbackException ex) { 
    Throwable cause = ex.getCause(); 
    if (cause != null && cause instanceof OptimisticLockException) { 
     System.out.println("Someone already changed AnyEntity."); 
    } else { 
     throw ex; 
    } 
} 

Ссылка: Java - JPA - @Version annotation

0

Вы правильно инициализация поля версии?

Если нет, то он не должен работать с null, попробуйте добавить значение по умолчанию к нему:

@Version 
private Long version = 0L; 
Смежные вопросы