我想通过使用乐观锁定来处理并发执行。我在实体类中添加了@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)
答案 0 :(得分:6)
要知道如何处理OptimisticLockException
,首先要考虑乐观锁定的工作原理。使用此策略时,您的实体将获得一个使用@Version注释的版本字段或属性,如果需要,您可以将其映射到数据库中的列。默认情况下,当使用乐观锁定时,JPA提供程序会将从数据库读取实体时@Version字段的值与现在的值进行比较。当实体中的更改提交到数据库时(通常在事务结束时发生),就会发生这种情况。如果@Version字段的旧值等于当前值,则持久性提供程序会增加version字段。但是如果它们不匹配,则抛出OptimisticLockException以指示在事务期间某些其他事务已更改实体并且您的trasaction被回滚。此行为可防止您覆盖其他事务的结果。这意味着处理异常的最合适方法是从数据库重新读取实体并重新应用要对其进行的更改。例如,您可以在循环中执行此操作
boolean success = false;
while (!success) {
try {
//start transaction, read entity, update it and commit
success = true;
}
catch (OptimisticLockException ex) {
//log your error
}
}
这可确保您的代码尝试重新读取实体并重新应用更改,直到不发生版本冲突并成功提交事务。