首页 > 解决方案 > 来自 JpaRepository 的 saveAll 的唯一约束

问题描述

我的应用程序接收包含对象的数组,这些对象映射到实体然后持久化。

该对象有一个 id 属性,该属性映射到具有唯一约束的列。具有重复 ID 的对象可能会被发送到应用程序。

我正在使用该saveAll方法,但如果任何对象碰巧违反了唯一约束,它会在插入过程中抛出。

有没有一种简单的方法可以让它插入所有非重复项并忽略重复项,或者只是更新它们?

我尝试过覆盖哈希和等于,但这没有帮助。

该应用程序每秒接收数十个请求,而我希望接收的重复请求数量很少。

实体:

@Table(name = "table", uniqueConstraints = @UniqueConstraint(columnNames = "natural_id"))
public class Entity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "natural_id", unique = true)
    private String naturalId;

    // ...
}

存储库:

public interface Repository extends JpaRepository<Entity, Long>, JpaSpecificationExecutor<Entity> {}

保存方法:

void save(List<Entities> entities) {
        try {
            repository.saveAll(entities);
        } catch (Exception e) {
            log.error("...");
            throw e;
        }
    }

如果我要将保存方法更改为:

    @Transactional
    void save(List<Entities> entities) {
        for (Entities et: entities) {
            try {
                repository.save(et);
            } catch (Exception e) {
                log.error("...");
            }
        }
    }

这会让这一切发生在一次交易中吗?我很担心,因为 save 方法通常在每次调用它时都会创建一个新事务,这对于每秒接收相当数量请求的应用程序来说会变得非常慢。

我最终可能必须在插入之前查询数据库以过滤出重复项以进行插入,并在每次捕获到约束违反异常时再次执行此操作。它应该可以工作,但是很丑陋。

标签: javamysqlspring-boothibernatejpa

解决方案


您必须保存单个记录,因为如果遇到某些记录的问题,则全部保存将不会恢复/恢复,然后其他记录也不会保存,因为所有记录都在同一个事务中。

正如您建议的那样,在插入之前查询数据库以过滤掉重复项,而不是像您提到的“每秒数十个请求”那样使用 try catch 更好地尝试循环,因此它不会产生太多开销。


推荐阅读