You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止数据库数据被覆盖 解决高并发下字段增量计数错误问题

你遇到的是典型的丢失更新问题,本质是「读-改-写」的非原子操作在高并发场景下的时序冲突,多个事务同时读到相同的旧计数值,各自加1后回写,最终只累加了一次。以下是满足要求的解决方案:

1. 数据库层原子增量更新(最符合「无需先读取数值」的要求)

直接通过HQL/JPQL执行更新语句,把增量逻辑放在数据库层面原子执行,完全跳过应用层读取计数的步骤:

// 假设实体类为FileRecord,计数字段为typeCount,匹配条件为文件类型fileType
String updateHql = "update FileRecord set typeCount = typeCount + 1 where fileType = :targetFileType";
int effectRows = session.createQuery(updateHql)
        .setParameter("targetFileType", 你的业务文件类型参数)
        .executeUpdate();

Oracle的单条UPDATE语句本身具备原子性,执行时会自动对操作行加锁,并发请求会排队串行执行,完全不会出现累加丢失的问题,性能也远高于先读后写的方案。

2. 乐观锁方案(适合并发冲突概率较低的场景)

如果业务逻辑必须先读取实体做其他校验/操作,可以给实体加@Version乐观锁注解避免丢失更新:

@Entity
public class FileRecord {
    // 其他业务字段
    @Version
    private Integer version; // 乐观锁版本字段,无需手动维护
    private Integer typeCount;
    private String fileType;
}

并发更新时如果版本号不匹配,Hibernate会抛出OptimisticLockException,捕获异常后重试更新即可保证计数准确。

3. 悲观锁方案(适合并发冲突概率高的场景)

如果业务必须先读实体,且冲突率很高,可以在读取时加行级排他锁,避免其他事务同时修改该行:

// 读取时直接加行锁,生成SELECT ... FOR UPDATE语句
FileRecord record = session.get(FileRecord.class, 记录主键ID, LockMode.PESSIMISTIC_WRITE);
record.setTypeCount(record.getTypeCount() + 1);
session.saveOrUpdate(record);

加锁后其他事务必须等当前事务提交后才能读取该行数据,也能避免丢失更新问题。


内容的提问来源于stack exchange,提问作者Hiba Rida

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 01:54:01