首页 > 解决方案 > Spring Boot JPA save() 方法尝试插入现有行

问题描述

我有一个简单的 kafka 消费者,它收集事件并根据其中的数据插入或更新数据库中的记录 - 表在 ID 列和实体字段中都有唯一的 ID 约束。

当表格预先填充并且不时发生插入时,一切正常。但是,当我截断表并发送具有有限 ID 数量的几千个事件(我在 3k 个事件中执行 50 个唯一 ID)时,会同时处理事件,并且 save() 方法随机失败,并出现唯一约束违规异常。我调试了它,结果很简单。

event1={id = 1 ... //somedata}被拾取,服务方法 saveOrUpdateRecord() 查找 ID=1 的记录,没有找到,插入一条新记录。

event2={id = 1 ... //somedata}几乎同时被拾取,服务方法 saveOrUpdateRecord() 查找 ID=1 的记录,没有找到(前一个是中间插入),尝试插入并因违反约束异常而失败-应该找到此记录并将其与基于我的条件的事件输入合并。

我怎样才能让 saveOrUpdateRecord() 仅在前一个完全执行以防止此类行为时运行?我真的不想用投票大小等来减慢 kafka 消费者的速度,我只想让我的服务一次执行一个事务。

服务方式:

    public void saveOrUpdateRecord(Object input) {
    Object output = repository.findById(input.getId));

    if (output == null) {
        repository.save(input);

    } else {
        mergeRecord(input, output);
        repository.save(output);

    }
}

方法上的@Transactional注释可以完成这项工作吗?

标签: spring-bootjpatransactionspersistence

解决方案


使您的服务线程安全。用这个:

    public synchronized void saveOrUpdateRecord(Object input) {
    Object output = repository.findById(input.getId));

    if (output == null) {
        repository.save(input);

    } else {
        mergeRecord(input, output);
        repository.save(output);

    }
}

推荐阅读