JPA/Hibernate如何正确增加数据库中的计数器?

JPA/Hibernate如何正确增加数据库中的计数器?,hibernate,jpa,counter,increment,race-condition,Hibernate,Jpa,Counter,Increment,Race Condition,也许对某些人来说这听起来是个简单的问题,但在数据库中增加计数器的正确方法是什么 例如,如果我有一个包含“like_count”列的表,每当用户喜欢照片时,该列都会更新 (假设我有照片@Entity) 例如,上面的代码正确吗?是否会出现任何竞争条件 谢谢我认为代码不正确。一个并行运行的线程稍后完成更新,但之前读取了相同的计数器,将覆盖计数器,因此丢失一个计数 它还取决于事务隔离级别,如果您使用的是序列化或“可重复读取”,则是安全的,但通常使用读取提交的,这通常会在Oracle或PostgreSQL

也许对某些人来说这听起来是个简单的问题,但在数据库中增加计数器的正确方法是什么

例如,如果我有一个包含“like_count”列的表,每当用户喜欢照片时,该列都会更新

(假设我有照片@Entity)

例如,上面的代码正确吗?是否会出现任何竞争条件


谢谢

我认为代码不正确。一个并行运行的线程稍后完成更新,但之前读取了相同的计数器,将覆盖计数器,因此丢失一个计数

它还取决于事务隔离级别,如果您使用的是
序列化
或“可重复读取”,则是安全的,但通常使用
读取提交的
,这通常会在Oracle或PostgreSQL等数据库中显示此问题

另外值得注意的是,至少Hibernate正在保存完整的实体,而不是默认情况下仅保存修改过的列。因此,更改不同的列不起作用。您可以使用
@DynamicUpdate
来更改这一点,但这种硬行为更改可能会产生一些副作用,至少对于刷新到DB的字段的脏检查的性能是这样的

解决方案:

正确的解决办法是:

  • 悲观锁定:使用
    选择锁定行。。。对于更新
    -不好这可能会对性能造成不利影响,因为如果on writer处于活动状态,则所有写入程序和所有读卡器都必须等待
  • 原子更新:更好,因为它不使用悲观锁定:
    更新照片集likecount=likecount+1,其中id=:id
  • 乐观锁定方法。但是,您必须处理
    优化锁定异常
    并重复该事务

  • 我认为你是对的。我只给出两个建议:第一个是您不需要使用photospospository.save(),因为照片实体已经与会话关联。如果你修改它的态度,修改将在交易结束时持续进行。第二个问题是,当用户喜欢照片时,也许你应该记录用户的id,因为通常一次使用只能喜欢一张照片。谢谢你的回复!。很高兴知道,我不需要担心比赛条件或其他问题,这样做。我已尝试不使用.save,但它不会保留在我的数据库中?(我的数据库是PostgreSQL,我使用的是entityManager(而不是会话),这是为什么?我现在的工作仍然是使用PostgreSQL开发一个软件,但我们没有使用entityManager,所以我不能给你一个额外的答案。我知道,如果你使用会话,你真的不需要在同一会话中使用save()。也许这就是你必须使用save()的原因。)保存实体,但我认为没关系。这是否回答了你的问题?
    Photo photo = photoRepository.findByPhotoId(id)
    photo.setLikeCount(photo.getLikeCount()+1);
    photoRepository.save(photo)