我正在使用Spring Boot、JPA、Oracle 12C和下面的类型化查询来选择要处理的“新”项目。一旦我选择了“新”项目,我就会更新其状态,使其不再符合选择条件,但我看到一个并发问题,相同的项目被选中。
我在这里读到,我需要设置一个'LockModeType.PESSIMISTIC_WRITE'的查询,以防止其他线程选择相同的行,但它似乎不起作用。
我是否遗漏了下面的内容,或者我是否需要另一个配置来防止并发线程从表中检索相同的行?问题是否与锁级别或实体管理器未更新/刷新有关?
我的@Transactional
服务:
@Override
@Transactional(isolation = Isolation.READ_COMMITTED, rollbackFor=RuntimeException.class)
public MyObject retrieveItemByStatus(StatusEnum status) {
return myRepository.retrieveItemByStatus(status);
}
我的存储库层中的查询:
@Override
public MyObject retrieveItemByStatus(StatusEnum status) {
String sql = "SELECT t FROM myTable t WHERE status = :status ORDER BY id ASC";
try {
TypedQuery<MyObject> query = em.createQuery(sql, MyObject.class).setParameter("status", status);
query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
query.setFirstResult(0);
query.setMaxResults(1);
MyObject myObject = (MyObject) query.getSingleResult();
if (myObject != null) {
myObject.setStatus(StatusEnum.IN_PROGRESS);
MyObject myUpdatedObject = em.merge(myObject);
return myUpdatedObject;
}
} catch (IllegalArgumentException iae) {
//some logging
} catch(NoResultException nrf) {
//some logging
} catch(Exception ex) {
//some logging
}
return null;
}
AFAIK你不能在oracle中阻止“读取”…悲观锁对应于<code>select for update</code>语句,它不会阻止其他<code>选择</code>语句…它只会强制它读取旧版本的数据(在<code>运行select forupdate>/code<之前)…它将只阻止其他<code>选择更新</code>语句(因此其他具有悲观锁的查询)
我可以证实这一观察。我用 H2 数据库测试了几种锁定模式,并且都按预期工作。这两种悲观的锁定模式都无法与 Oracle 数据库结合使用。因此,问题来了:这段代码有什么问题?
使用 Oracle 时,其中两个并发代码执行会产生相同的数据,尽管第一个应该阻止第二个:
// Every Thread gets its own Hibernate session:
final Session session = HibernateSessionHolder.get();
session.getTransaction().begin();
final List<EventDeliveryDataDB> eddList =
session.createCriteria(EventDeliveryDataDB.class)
.setLockMode(LockMode.PESSIMISTIC_WRITE) // with READ the same
.add(eq("progress", NEW))
.list();
eddList.stream().forEach(eddElem -> eddElem.setProgress(IN_PROGRESS));
session.getTransaction().commit();
Hibernate日志:
Hibernate: select this_.DD_ID as DD_ID1_2_0_, this_.CHANNEL_NAME as CHANNEL_NAME2_2_0_, this_.created as created3_2_0_, this_.DELIVERY_TIME as DELIVERY_TIME4_2_0_, this_.ERROR_CODE as ERROR_CODE5_2_0_, this_.ERROR_MESSAGE as ERROR_MESSAGE6_2_0_, this_.EVENT_ID as EVENT_ID7_2_0_, this_.MAX_RETRIES as MAX_RETRIES8_2_0_, this_.PROGRESS as PROGRESS9_2_0_, this_.PROGRESS_ID as PROGRESS_ID10_2_0_, this_.RECIPIENT_CRID as RECIPIENT_CRID11_2_0_, this_.RETRY_COUNTER as RETRY_COUNTER12_2_0_, this_.RETRY_TIME as RETRY_TIME13_2_0_, this_.updated as updated14_2_0_ from HR.NOS_DELIVERY_DATA this_ where this_.PROGRESS=?
Hibernate: select this_.DD_ID as DD_ID1_2_0_, this_.CHANNEL_NAME as CHANNEL_NAME2_2_0_, this_.created as created3_2_0_, this_.DELIVERY_TIME as DELIVERY_TIME4_2_0_, this_.ERROR_CODE as ERROR_CODE5_2_0_, this_.ERROR_MESSAGE as ERROR_MESSAGE6_2_0_, this_.EVENT_ID as EVENT_ID7_2_0_, this_.MAX_RETRIES as MAX_RETRIES8_2_0_, this_.PROGRESS as PROGRESS9_2_0_, this_.PROGRESS_ID as PROGRESS_ID10_2_0_, this_.RECIPIENT_CRID as RECIPIENT_CRID11_2_0_, this_.RETRY_COUNTER as RETRY_COUNTER12_2_0_, this_.RETRY_TIME as RETRY_TIME13_2_0_, this_.updated as updated14_2_0_ from HR.NOS_DELIVERY_DATA this_ where this_.PROGRESS=?
Hibernate: select DD_ID from HR.NOS_DELIVERY_DATA where DD_ID =? for update
Hibernate: select DD_ID from HR.NOS_DELIVERY_DATA where DD_ID =? for update
Hibernate: update HR.NOS_DELIVERY_DATA set CHANNEL_NAME=?, created=?, DELIVERY_TIME=?, ERROR_CODE=?, ERROR_MESSAGE=?, EVENT_ID=?, MAX_RETRIES=?, PROGRESS=?, PROGRESS_ID=?, RECIPIENT_CRID=?, RETRY_COUNTER=?, RETRY_TIME=?, updated=? where DD_ID=?
Hibernate: update HR.NOS_DELIVERY_DATA set CHANNEL_NAME=?, created=?, DELIVERY_TIME=?, ERROR_CODE=?, ERROR_MESSAGE=?, EVENT_ID=?, MAX_RETRIES=?, PROGRESS=?, PROGRESS_ID=?, RECIPIENT_CRID=?, RETRY_COUNTER=?, RETRY_TIME=?, updated=? where DD_ID=?
我使用的是Spring Boot 2和Spring数据JPA。 我有一个带有@Transactional annotation的服务,它从存储库中读取记录,如果记录不存在,则添加记录并保存所有记录。我创建了一个测试方法,并行执行服务方法5次。由于我使用的是@Lock(LockModeType.悲观写入),我希望其中一个线程在读取可用性时会得到锁,而其他4个线程必须等待事务(createReserv
我试图在JPA中通过Hibernate3对Postgres数据库使用悲观锁定。我无法使锁超时--它似乎永远挂着。 这里有一个例子: 按照我的理解,em2应该尝试最多5秒(5000ms)来获得锁,然后应该抛出一个异常。相反,代码变成死锁。 谢谢,阿拉斯泰尔
我试图为运行在不同JBoss节点上的cron作业实现某种信号量。我尝试使用数据库(Oracle 11g)作为锁定机制,使用一个表来同步不同节点中的cron作业。表格很简单: 因此,当一个作业启动时,它会在表中搜索它的cronjobtype条目,并检查它是否已经在运行。如果不是,它将条目设置运行标志更新为真。第一个选择是使用Hibernate和悲观锁通过JPA CriteriaApi做出的。 所有这
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。 乐观锁与悲观锁的具体区别: http://www.cnblogs.com/Bob-FD/p/3352216.html
问题内容: 我正在尝试在JPA中使用悲观锁定,而不是针对Postgres数据库使用Hibernate 3。我无法超时锁定-它似乎永远挂着。 这是一个例子: 据我了解,em2应该尝试长达五秒钟(5000毫秒)来获取锁,然后应该抛出异常。而是代码陷入僵局。 如果我在两个不同的线程中运行它,那么我会看到线程2(带有em2)在线程1(em1)释放它后立即获得了锁。因此锁定正在发生,只是永不超时。 我用PE
问题内容: 我在java下有spring项目,使用hibernate查询,我喜欢使用悲观锁定。 在Spring + Hibernate中如何进行悲观锁定? 编辑: 问题: 我想在一个方法中使用悲观锁定,并且我将此方法称为从不同的方法。当我从第一个方法调用它时,悲观的工作效果很好,但是当我从第二个方法调用它时,它给出了(无法提交事务) 例外: 问题答案: http://www.amicabile.c