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

如何约束Question与Option表的(questionNumber,optionNumber)唯一?Spring Data JPA实现

如何约束(questionNumber, optionNumber)组合全局唯一及Spring Data JPA实现

一、数据库层面约束实现

要实现(questionNumber, optionNumber)组合全局唯一,需分两步处理:

  1. 确保Question表的questionNumber字段唯一
    先保证每个questionNumber在Question表中唯一,这是全局唯一约束的基础。执行以下SQL添加唯一约束:

    ALTER TABLE Question ADD CONSTRAINT uk_question_number UNIQUE (questionNumber);
    
  2. 在Option表添加联合唯一约束
    若Option表未关联Question的questionNumber,先添加该字段,再给questionNumber和optionNumber添加联合唯一约束,确保同一questionNumber下的optionNumber不重复,结合Question表的约束实现组合全局唯一:

    -- 若Option表无questionNumber字段,先执行添加
    ALTER TABLE Option ADD COLUMN questionNumber INT;
    -- 添加联合唯一约束
    ALTER TABLE Option ADD CONSTRAINT uk_question_option_number UNIQUE (questionNumber, optionNumber);
    

二、Spring Data JPA实现方式

1. 定义实体类

Question实体

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;

@Entity
public class Question {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    private String question;
    
    @NotNull
    @Column(unique = true) // 映射数据库唯一约束
    private Integer questionNumber;

    // 省略getter、setter及构造方法
}

Option实体

通过@Table注解的uniqueConstraints属性定义联合唯一约束,JPA自动建表时会生成对应数据库约束:

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;

@Entity
@Table(uniqueConstraints = {
        @UniqueConstraint(columnNames = {"questionNumber", "optionNumber"})
})
public class Option {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    private String option;
    
    @NotNull
    private Integer optionNumber;
    
    @NotNull
    private Integer questionNumber; // 关联Question的questionNumber

    // 省略getter、setter及构造方法
}

2. 定义Repository接口

QuestionRepository

import org.springframework.data.jpa.repository.JpaRepository;

public interface QuestionRepository extends JpaRepository<Question, Integer> {
    // 检查questionNumber是否已存在
    boolean existsByQuestionNumber(Integer questionNumber);
}

OptionRepository

import org.springframework.data.jpa.repository.JpaRepository;

public interface OptionRepository extends JpaRepository<Option, Integer> {
    // 检查(questionNumber, optionNumber)组合是否已存在
    boolean existsByQuestionNumberAndOptionNumber(Integer questionNumber, Integer optionNumber);
}

3. 业务层处理

保存数据前可通过Repository的exists方法提前检查组合是否存在,避免数据库抛出异常;即使未提前检查,数据库约束也会最终拦截重复数据,需捕获并处理异常:

import org.springframework.stereotype.Service;

@Service
public class OptionService {
    private final OptionRepository optionRepository;

    public OptionService(OptionRepository optionRepository) {
        this.optionRepository = optionRepository;
    }

    public Option saveOption(Option option) {
        if (optionRepository.existsByQuestionNumberAndOptionNumber(option.getQuestionNumber(), option.getOptionNumber())) {
            throw new IllegalArgumentException("该questionNumber与optionNumber的组合已存在");
        }
        return optionRepository.save(option);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 05:25:52