How to handle org.eclipse.persistence.exceptions.OptimisticLockExceptio

Refresh

December 2018

Views

4.8k time

1

I want to handle concurrent execution by using Optimistic Locking. I have included @Version annotation in my entity class.

In my code I am running two threads concurrently. Sometimes it is executing correctly. Sometimes it is throwing org.eclipse.persistence.exceptions.OptimisticLockException and 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 [[email protected]] 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 answers

3

Для того, чтобы знать, как обращаться OptimisticLockExceptionВы должны сначала рассмотреть, как оптимистическую блокировку работы. При использовании этой политики ваша организация получает поле версии или свойство, аннотированный с @version и которые можно привязать к столбцу в базе данных, если вы хотите. По умолчанию, когда оптимистичный замок используется провайдер JPA сравнивает значение поля @version было, когда объект был прочитан из базы данных с тем, что он имеет в настоящее время. Это происходит, когда изменения в сущности в настоящее время поручены к базе данных, которая обычно происходит в конце транзакции. Если старое значение поля @version равно текущей увеличивает поле версии поставщик живучести. Но если они не соответствуют OptimisticLockException брошено, чтобы указать, что во время операции некоторых другие сделки изменились сущность и ваши rolledback являются операции Устанавливаются. Такое поведение предотвращает переопределение результатов другой сделки. Это означает, что наиболее подходящим способом для обработки исключения является перечитывая объект из базы данных и повторно применить изменения, которые нужно внести в него. Например, вы можете сделать это в цикле

boolean success = false; 
while (!success) {
    try {
        //start transaction, read entity, update it and commit
        success = true;
    }
    catch (OptimisticLockException ex) {
        //log your error
    }
}

Это гарантирует, что ваш код пытается перечитывая сущность и повторные изменения к нему до тех пор пока ни одна из версий конфликта не происходит, и сделка успешно совершена.