【发布时间】:2019-02-23 10:17:18
【问题描述】:
我正在使用带有 TransactionTemplate 和悲观锁的 Spring Boot JPA,我试图防止记录在事务期间被其他线程更新。代码如下:
transactionService.executeTransaction(() -> {
Map<String, Object> properties = new HashMap<>();
properties.put("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED);
System.out.println("--------------------- start find with lock, job id: " + entityId);
Entity newEntity = (Entity) em.find(entityClass, entityId, LockModeType.PESSIMISTIC_WRITE, properties);
System.out.println("+++++++++++++++++++++ end find with lock, job id: " + entityId);
try{
Thread.sleep(2000);
}catch (InterruptedException e){
}
newEntity = setEntity.setEntity(newEntity);
System.out.println(Thread.currentThread().getName() + ": use transaction to save: " + newEntity.getId());
});
还有一个带有 while 循环的线程,并试图更新记录。如下所示:
while(true){
Entity entity = entity.findOne(id);
repository.save(entity);
System.out.println("save success: " + id)
}
但是我发现悲观锁根本不起作用,在“start find with lock”和“end find with lock”之间的打印过程中,以及2秒的睡眠,我发现实体总是可以被保存另一个线程。我对悲观锁有什么误解吗?
编辑 1: 我已经调试并看到了 sql。
em.find(entityClass, entityId, LockModeType.PESSIMISTIC_WRITE, properties);
已经生成了两个sql,一个没有连接到任何其他表,但是有“for update”
SELECT * FROM ... WHERE ID=? FOR UPDATE
另一个是,加入但没有“更新”
SLECT * FROM ... left outer join ... left outer join ... where id=?
希望这会有所帮助。
【问题讨论】:
-
悲观锁应该根据 JPA 规范创建一个类似“SELECT ... FOR UPDATE”的 SQL 语句。也许您应该通过查看您的 JPA 提供程序日志以了解他们发送的 SQL 来调试您的情况。
-
@BillyFrost 添加 sql,有一个带有“for update”的 sql
标签: spring-boot jpa pessimistic-locking