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

JpaRepository同名书籍去重查询及异类型注册校验实现方案

实现方案

原有代码存在两个核心问题:

  • 自定义JPQL未做结果数量限制,同名书籍有多条记录时会直接抛出NonUniqueResultException,无法稳定返回单条结果
  • 仅取第一条记录的tipo_registro做比对逻辑不严谨,无法覆盖数据库中已经存在多个不同注册类型同名书籍的冲突场景

1. Repository层修正

两种实现方式都可以保证多结果场景下稳定返回单条匹配记录,优先用Spring Data JPA派生查询,无需手写JPQL:

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;

public interface LivroRepository extends JpaRepository<LivroEntity, Long> {
    // 派生查询:按书籍名称查询第一条记录的注册类型,自动追加LIMIT 1,不会触发多结果异常
    Optional<String> findFirstTipoRegistroByNome(String nome);

    // 辅助查询:统计同名下不同注册类型的数量,用于覆盖存量冲突场景
    long countDistinctTipoRegistroByNome(String nome);
}

如果需要保留自定义@Query写法,必须显式加分页参数限制返回1条结果:

@Query("select l.tipo_registro from LivroEntity l where l.nome = :nome")
Optional<String> findFirstTipoRegistroByNome(String nome, Pageable pageable);

// 调用时传入分页参数即可:
// livroRepository.findFirstTipoRegistroByNome(nome, PageRequest.of(0, 1))

2. 业务校验逻辑修正

校验分两层执行,覆盖所有冲突场景:

  1. 先判断同名下是否已存在多个不同注册类型的记录,若存在直接拦截
  2. 若同名下仅存在一种注册类型,再和当前待注册书籍的类型做比对,不一致则拦截
String nomeLivro = livro.getNome();
String tipoRegistroAtual = livro.getTipo_registro();

// 校验存量是否已存在多注册类型冲突
long distinctTipoCount = livroRepository.countDistinctTipoRegistroByNome(nomeLivro);
if (distinctTipoCount > 1) {
    throw new CadastroException(String.format(
        "书籍[%s]已存在多个不同注册类型的存量记录,禁止新增",
        nomeLivro
    ));
}

// 校验存量注册类型和当前传入类型是否一致
Optional<String> tipoRegistroExistenteOpt = livroRepository.findFirstTipoRegistroByNome(nomeLivro);
if (tipoRegistroExistenteOpt.isPresent()) {
    String tipoRegistroExistente = tipoRegistroExistenteOpt.get();
    if (!tipoRegistroExistente.equals(tipoRegistroAtual)) {
        throw new CadastroException(String.format(
            "同名书籍[%s]已绑定注册类型[%s],与当前传入类型[%s]不一致,禁止注册",
            nomeLivro, tipoRegistroExistente, tipoRegistroAtual
        ));
    }
}

// 所有校验通过后执行保存
return livroRepository.save(livro);

关键注意事项

  • 不要用空字符串作为查询结果的默认判空值,使用Optional包装返回值可以有效避免空指针异常
  • 禁止在未加结果限制的JPQL中查询单条字段,多结果场景下JPA会直接抛出非唯一结果异常
  • 仅取第一条记录做比对的逻辑存在漏洞,必须先做去重计数校验,否则存量数据已经存在冲突时校验规则会失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:24:21