Как обрабатывать org.eclipse.persistence.exceptions.OptimisticLockExceptio
Я хочу обрабатывать параллельное выполнение с помощью Оптимистической блокировки. Я включил @Version
аннотация в моем классе сущности.
В моем коде я запускаю два потока одновременно. Иногда это выполняется правильно. Иногда это бросание org.eclipse.persistence.exceptions.OptimisticLockException
а также javax.persistence.OptimisticLockException
,
public class StudentCreation implements Runnable {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("jpaApp");
Student student = null;
@Override
public void run() {
for (int i = 1; i <= 2; i++) {
try {
if (i % 2 == 0) {
update("XYZ");
} else {
update("ABC");
}
} catch (Exception e) {
System.out.println("Update exception");
}
}
}
// main method
public static void main(String ar[]) {
StudentCreation std1 = new StudentCreation();
// creating two threads
Thread thread1 = new Thread(std1, "Thread1");
Thread thread2 = new Thread(std1, "Thread2");
thread1.start();
thread2.start();
}
public Object update(String name) throws Exception {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// reading data from database
student = em.find(Student.class, 1L);
em.lock(student, LockModeType.OPTIMISTIC);
//updating
student.setStudentName(name);
em.getTransaction().commit();
return student;
}
}
[EL Warning]: 2014-12-12 17:54:35.75--UnitOfWork(744551)--Thread(Thread[Thread2,5,main])--Local Exception Stack:
Exception [EclipseLink-5006] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.OptimisticLockException
Exception Description: The object [locks.Student@131a989] cannot be updated because it has changed or been deleted since it was last read.
Class> locks.Student Primary Key> 1
at org.eclipse.persistence.exceptions.OptimisticLockException.objectChangedSinceLastReadWhenUpdating(OptimisticLockException.java:144)
at org.eclipse.persistence.descriptors.VersionLockingPolicy.validateUpdate(VersionLockingPolicy.java:790)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:1087)
at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommitWithChangeSet(UpdateObjectQuery.java:84)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:301)
at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1737)
at org.eclipse.persistence.internal.sessions.CommitManager.commitChangedObjectsForClassWithChangeSet(CommitManager.java:267)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:130)
at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4207)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1441)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1531)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)
at locks.StudentCreation.update(StudentCreation.java:43)
at locks.StudentCreation.run(StudentCreation.java:19)
at java.lang.Thread.run(Unknown Source)
1 ответ
Чтобы знать, как обращаться OptimisticLockException
Вы должны сначала рассмотреть, как работает оптимистическая блокировка. При использовании этой политики ваша сущность получает поле версии или свойство, помеченное @Version и которое вы можете сопоставить со столбцом в базе данных, если хотите. По умолчанию, когда используется оптимистическая блокировка, поставщик JPA сравнивает значение поля @Version, когда объект считывался из базы данных, с тем, которое он имеет сейчас. Это происходит, когда изменения в сущности передаются в базу данных, что обычно происходит в конце транзакции. Если старое значение поля @Version равно текущему, поставщик сохраняемости увеличивает поле версии. Но если они не совпадают, выдается исключение OptimisticLockException, указывающее, что во время вашей транзакции какая-то другая транзакция изменила сущность, и ваша транзакция откатывается. Такое поведение не позволяет переопределить результаты другой транзакции. Это означает, что наиболее подходящим способом обработки исключения является перечитывание объекта из базы данных и повторное применение изменений, которые вы хотите внести в него. Например, вы можете сделать это в цикле
boolean success = false;
while (!success) {
try {
//start transaction, read entity, update it and commit
success = true;
}
catch (OptimisticLockException ex) {
//log your error
}
}
Это гарантирует, что ваш код пытается перечитать сущность и применить к ней изменения до тех пор, пока не произойдет конфликт версий и транзакция будет успешно зафиксирована.