如果没有使用@Transactional,Hibernate/Spring会立即写入数据库吗



我在下面总结了这个案例,但我面临的似乎是一个"丢失更新";问题,尽管我使用的锁不允许一次有多个线程能够写入数据库。

锁,即可重入锁、同步锁、信号量等,都能很好地防止多个线程访问共享区域。。这里没有问题。以下是简单的设置:

由于两个用户单击一个按钮来增加计数器,我得到了两个Java线程。每个用户都会对计数器进行重复更新,计数器是Mysql表中的一个字段。基本上,如果用户慢慢点击按钮,就不会丢失更新。当他们加快点击每个用户的UI时,我会看到错过的更新。

为了防止两个线程相互踩在对方的脚上,每个线程都需要获得共享代码区域的锁。如果我有多个服务器,我就不会使用java锁。整个应用程序在一台服务器上。

我看到的是,即使一个线程写入数据库并释放锁,下一个线程也会看到该字段的一些旧值。我删除了所有@Transactional语句以排除任何Spring事务问题,但丢失的更新仍然存在。

那么,如果存储库(DAO(写入Mysql,难道不能保证该值被提交并持久化吗?请记住,此处不使用@Transactional语句。我还在存储库模块中尝试了保存后刷新。

有什么想法吗?我错过了什么?

@Transactional注释始终用于数据修改方法。它不仅用于事务本身,还用于打开和关闭持久上下文(Hibernate会话(!

例如,您可以检查JpaRepositorysave()方法的实现

@Transactional
@Override
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}

使用java锁的想法不是很好。你为什么有这样的行为?我认为这不是事务性问题,可能是您错误地实现了多线程代码。

最好的方法是使用JPQLupdate来更新计数器

update ButtonEntity set couner = counter + 1 where id = :buttonId

另一种选择是使用悲观锁。