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

标签 hibernate jpa counter increment race-condition

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

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

(假设我有我的照片@Entity)

Photo photo = photoRepository.findByPhotoId(id)
photo.setLikeCount(photo.getLikeCount()+1);
photoRepository.save(photo)

例如,上面的代码正确吗?会发生任何竞争条件吗?

谢谢

最佳答案

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

这还取决于事务隔离级别,如果您使用SERIALIZATION或“REPEATABLE_READ”,您是安全的,但通常使用READ COMMITTED,这会显示此问题通常与 Oracle 或 PostgreSQL 等数据库有关。

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

解决方案:

正确的解决方案是:

  1. 悲观锁定:使用SELECT ... FOR UPDATE锁定行 - 不好,这可能会降低性能,因为所有写入者都必须等待,如果写入者处于事件状态,所有读取者也必须等待
  2. 原子更新:更好,因为它不使用悲观锁定: 更新照片设置 likecount = likecount + 1 WHERE id = :id
  3. 乐观锁定方法。但随后您必须处理 OptimisticLockingExceptions 并重复事务

关于hibernate - JPA/Hibernate 如何正确增加数据库中的计数器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27284487/

相关文章:

java - 在 hibernate 中从 session.createQuery 获取超过 1 个对象

java - 如何迭代条件生成的列表?

java - Java中简单的数字计数器方法

linux脚本计数器问题

mysql - Php/Mysql Union 和 Limit offset

java - 无法连接到sql server 2008实例

java - Hibernate通过java注释将java中的嵌套集合映射到映射表?

java - 如何在 hibernate 中使用单个表连接三个表?

java - ManyToMany Relation 正在更新域表

jpa - 在DerbyDB上使用jpa自动生成的primary_key的问题