如何处理 org.eclipse.persistence.exceptions.OptimisticLockExceptio

Posted

技术标签:

【中文标题】如何处理 org.eclipse.persistence.exceptions.OptimisticLockExceptio【英文标题】:How to handle org.eclipse.persistence.exceptions.OptimisticLockExceptio 【发布时间】:2015-02-11 05:09:08 【问题描述】:

我想通过使用乐观锁定来处理并发执行。我在我的实体类中包含了@Version 注释。

在我的代码中,我同时运行两个线程。有时它正在正确执行。有时它会抛出org.eclipse.persistence.exceptions.OptimisticLockExceptionjavax.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
    

这可确保您的代码尝试重新读取实体并对其重新应用更改,直到没有发生版本冲突并且事务成功提交。

【讨论】:

以上是关于如何处理 org.eclipse.persistence.exceptions.OptimisticLockExceptio的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 UsernameNotFoundException 春季安全

如何处理c#中的错误代码

Akka 如何处理消息版本?

开玩笑测试 - 如何处理 JsonWebToken 响应

如何处理 JSON 响应

“不知道如何处理' nvcc 致命错误