在事务中使用悲观锁不能阻止记录被更新?
Posted
技术标签:
【中文标题】在事务中使用悲观锁不能阻止记录被更新?【英文标题】:Using pessimistic lock in transaction can not prevent record from being updated? 【发布时间】: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 【参考方案1】:是的,如果您使用 Hibernate 作为您的 JPA 实现,那么它还不受支持。所以锁不会扩展到连接
按照 JPA 标准的规定,尚不支持 javax.persistence.lock.scope。
来自Hibernate Docs
Related Ticket
【讨论】:
以上是关于在事务中使用悲观锁不能阻止记录被更新?的主要内容,如果未能解决你的问题,请参考以下文章