我正在研究一个项目,由于某些问题,我正在将悲观锁定转变为乐观锁定。虽然这样做我在更新代码中的实体时遇到错误,因为我尝试将其作为独立应用程序,因此两个线程不可能同时更新它。我在代码的不同部分检查了版本的值。它显示为0.当调用flush或commit时,它给出一个例外,它被更新为1。
注意:我已在实体中添加了@version int version_id字段以进行乐观锁定。
代码如下:
WorkItem tmp_workItem=entityManager.find(WorkItem.class , workItem.getEntityKey());
logger.info("Before merge"+ tmp_workItem.getVersion());
entityManager.merge(workItem);
tmp_workItem=entityManager.find(WorkItem.class , workItem.getEntityKey());
logger.info("After merge"+tmp_workItem.getVersion()+" "+workItem.getVersion());
//logger.info(entityManager.getLockMode(WorkItem.class).toString());
entityManager.flush();
logger.info("After flush"+tmp_workItem.getVersion());
response = true;
此代码抛出异常:
getVersion : 1
] cannot be updated because it has changed or been deleted since it was last read.
Class> com.csg.ib.cobra.domain.WorkItem Primary Key> [9553]
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:549)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithPreBuiltChangeSet(UnitOfWorkImpl.java:1559
记录器中的版本值为:
合并前:0 0 合并后:0 0 在冲洗之前:0 0
然后在调用entityManger.flush()
时它如何增加1)
答案 0 :(得分:0)
通常,与在持久化操作上更新的id字段相比,在使用commit或flush将数据实际刷新到数据库时更新版本字段。这就是为什么在调用entityManager.flush之前版本字段值为0的原因。如果使用资源本地事务,您也可以使用transaction.commit。
关于您在应用程序代码中获得的异常,有一个更完整的代码示例(可能是JUnit测试的形式)会很有用。我创建了以下简单测试以证明正确的行为,希望它会有所帮助:
@Test
public void testOptimisticLocking() {
OptimisticEntity entity = new OptimisticEntity();
entity.setName("Some name");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
try {
entityManager.persist(entity);
transaction.commit();
} catch (Exception x) {
transaction.rollback();
Assert.fail("Failed to commit: " + x.getMessage());
}
int id = entity.getId();
int version = entity.getVersion();
Assert.assertTrue(id > 0);
Assert.assertTrue(version > 0);
entity = entityManager.find(OptimisticEntity.class, id);
Assert.assertNotNull("Entity could not be retrieved", entity);
Assert.assertEquals("Entity version retrieved not expected", version, entity.getVersion());
entity.setName("Another name");
transaction.begin();
try {
entityManager.merge(entity);
transaction.commit();
} catch (Exception x) {
transaction.rollback();
Assert.fail("Failed to merge: " + x.getMessage());
}
Assert.assertEquals("Entity version not incremented after merge", version+1, entity.getVersion());
}
@Test
public void testOptimisticLockingOneTransaction() {
OptimisticEntity entity = new OptimisticEntity();
entity.setName("Some name");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
try {
entityManager.persist(entity);
int id = entity.getId();
int version = entity.getVersion();
Assert.assertTrue(id > 0);
Assert.assertEquals(0, version);
OptimisticEntity retrievedEntity = entityManager.find(OptimisticEntity.class, id);
Assert.assertNotNull("Entity could not be retrieved", retrievedEntity);
Assert.assertEquals("Entity version retrieved not expected", 0, retrievedEntity.getVersion());
entity.setName("Another name");
entityManager.merge(entity);
Assert.assertEquals("Entity version changed after merge", 0, entity.getVersion());
retrievedEntity = entityManager.find(OptimisticEntity.class, id);
Assert.assertNotNull("Entity could not be retrieved", retrievedEntity);
Assert.assertEquals("Entity version retrieved not expected", 0, retrievedEntity.getVersion());
entityManager.flush();
Assert.assertEquals("Entity version not incremented after flush", 1, entity.getVersion());
transaction.commit();
} catch (Exception x) {
transaction.rollback();
Assert.fail("An error occurred: " + x.getMessage());
}
}