我正在尝试使用JPA的@Version注释测试乐观锁定,该注释已添加到我的实体对象中:
@Version
@Setter(AccessLevel.NONE)
@Column(name = "VERSION")
private long version; 当我同时运行两台服务器时,我收到一个StaleObjectStateException:
Exception message is : Object of class [com.myPackage.WorkQueue] with identifier [9074]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.myPackage.WorkQueue#9074]我期望看到1)发生OptimisticLockException,2) @transaction作为结果被回滚。
用例如下:将状态为“NEW”的条目插入到Oracle数据库表中。一旦线程检索到status = 'NEW‘的行,它就会将表中该行的状态更新为'IN_PROGRESS’。如果另一个事务成功地更新了该行,我需要确保同时读取同一行的任何事务都会失败/回滚。
服务:
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor=Exception.class, readOnly=false)
public WorkQueue retrieveWorkQueueItemByStatus(WorkQueueStatusEnum workQueueStatus) {
return workQueueRepository.retrieveWorkQueueItemByStatus(workQueueStatus);
}实现:
@Override
public WorkQueue retrieveWorkQueueItemByStatus(WorkQueueStatusEnum workQueueStatus) {
log.debug("Start - Attempting to select a " + workQueueStatus + " workQueue item in retrieveWorkQueueItemByStatus()");
try {
String sql = "SELECT a FROM WorkQueue a WHERE workQueueStatus = :workQueueStatus ORDER BY idWorkQueue ASC";
TypedQuery<WorkQueue> query = em.createQuery(sql, WorkQueue.class).setParameter("workQueueStatus", workQueueStatus)
.setFirstResult(0).setMaxResults(1);
WorkQueue workQueue = (WorkQueue) query.getSingleResult();
if (workQueue != null) {
workQueue.setWorkQueueStatus(WorkQueueStatusEnum.IN_PROGRESS);
WorkQueue updatedWorkQueue = em.merge(workQueue);
log.debug("Finish - selected the following workQueue item "+ workQueue.getIdWorkQueue() + " with the Audit Event Key from retrieveWorkQueueItemByStatus() : " + updatedWorkQueue.getAuditEventKey());
return updatedWorkQueue;
}
} catch (IllegalArgumentException iae) {
log.error("An IllegalArgumentException occured in workQueueRepositoryImpl.retrieveWorkQueueItemByStatus() attempting to execute query : " + sql + ". Exception message is : " + iae.getMessage());
} catch(Exception ex) {
log.error("An Exception occured in workQueueRepositoryImpl.retrieveWorkQueueItemByStatus() executing query : " + sql + ". Exception message is : " + ex.getMessage());
}
log.debug("Finish - returning null from retrieveWorkQueueItemByStatus()");
return null;
}发布于 2018-04-24 20:51:25
有关异常类型,请参阅this question。
事务不会自动回滚。这种异常永远不应该被捕获并继续使用Hibernate会话。原因是会话可能已部分同步到数据库,因此数据库状态可能不一致。因此,让异常在事务外部抛出,在事务中回滚,然后重新启动一个新会话。
https://stackoverflow.com/questions/50001990
复制相似问题