对于某些人来说,这听起来似乎是一个简单的问题但是在数据库中增加计数器的正确方法是什么?
例如,如果我有一个包含" like_count"每次用户喜欢照片时都会更新的列。
(假设我有我的照片@Entity)
Photo photo = photoRepository.findByPhotoId(id)
photo.setLikeCount(photo.getLikeCount()+1);
photoRepository.save(photo)
例如,上面的代码是否正确?是否会出现任何种族情况?
谢谢
答案 0 :(得分:1)
我认为代码不正确。并行运行的线程稍后完成更新,但之前读过相同的计数器,将覆盖计数器,因此丢失一个计数。
它还取决于事务隔离级别,如果您使用SERIALIZATION
或'REPEATABLE_READ'是安全的,但通常使用READ COMMITTED
,这通常会显示此问题通常与Oracle等数据库或PostgreSQL的。
另外值得注意的是,至少Hibernate默认保存整个实体,而不仅仅是修改了列。因此,更改不同的列会不工作。您可以使用@DynamicUpdate
更改此设置,但这种硬性行为更改可能会产生一些副作用,至少在脏字检查字段以刷新到DB时会产生一些副作用。
解决方案:
正确的解决方案是:
SELECT ... FOR UPDATE
锁定行 - 这可能对性能不利,因为所有作者都必须等待,并且所有读者如果在作者上都是活跃的UPDATE photo SET likecount = likecount + 1 WHERE id = :id
OptimisticLockingExceptions
并重复交易