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

使用GenerationType.TABLE策略时,如何在外部SQL文件自动生成ID插入数据?

问题

在学校项目中使用Hibernate,采用TABLE_PER_CLASS继承策略,父类Mensajes通过GenerationType.TABLE策略(对应mid_seq表)生成ID,数据库为MySQL。通过外部SQL文件插入数据时遇到两个问题:

  1. 省略id字段插入时,提示字段'id'没有默认值
  2. 直接取mid_seq的next_val作为ID插入时,出现主键重复,条目'0'违反唯一约束报错

相关代码与SQL

父类Mensajes代码

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Mensajes {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "id_gen")
    @TableGenerator(table = "mid_seq", name = "id_gen", initialValue = 0, allocationSize = 1)
    private Long id;

    private String fecha, cont;

//...getters, setters, etc

子类Resenia代码

@Entity
public class Resenia extends Mensajes{

    @ColumnDefault("0")
    private int rating;

//...getters, setters, etc

子类Post代码

@Entity
public class Post extends Mensajes {

    @ColumnDefault("0")
    private int votos;

//...getters, setters, etc

Hibernate生成的mid_seq表SQL

create table mid_seq (
    next_val bigint,
    sequence_name varchar(255) not null,
    primary key (sequence_name)
) engine=InnoDB
insert into mid_seq(sequence_name, next_val) values ('mensajes',0)

尝试的插入语句及报错

直接取next_val插入:

insert into resenia(id, fecha, cont, rating) values ((select next_val from mid_seq), "01/01/2000", "BUU", 2);
insert into resenia(id, fecha, cont, rating) values ((select next_val from mid_seq), "01/01/2003", "bien", 4);

报错:

SQL Error [1062] [23000]: Duplicate entry '0' for key 'PRIMARY'

省略id插入:

insert into resenia(fecha, cont, rating) values ("01/01/2000", "BUU", 2);

报错:

SQL Error [1364] [HY000]: Field 'id' doesn't have a default value


解决方案与分析

一、SQL插入时自动生成ID的方法

问题核心是手动取next_val不会自动更新序列值,而Hibernate的TABLE生成策略是自行维护序列,因此手动插入时需要同步维护序列的递增:

  1. 事务式更新+插入
    先更新序列值,再用更新后的值插入,确保每次ID唯一:

    -- 先递增序列
    update mid_seq set next_val = next_val + 1 where sequence_name = 'mensajes';
    -- 获取递增后的ID
    select next_val from mid_seq where sequence_name = 'mensajes';
    -- 执行插入
    insert into resenia(id, fecha, cont, rating) values ([上述查询结果], "01/01/2000", "BUU", 2);
    

    也可以用23598简化为单流程操作:

    update mid_seq set next_val = LAST_INSERT_ID(next_val + 1) where sequence_name = 'mensajes';
    insert into resenia(id, fecha, cont, rating) values (23598, "01/01/2000", "BUU", 2);
    
  2. 给表ID字段绑定序列函数
    创建MySQL函数自动获取并递增序列值,再将子类表的id字段默认值设为该函数返回值:

    -- 创建序列函数
    DELIMITER //
    CREATE FUNCTION get_next_mensajes_id() RETURNS BIGINT
    BEGIN
        DECLARE next_id BIGINT;
        UPDATE mid_seq SET next_val = next_val + 1 WHERE sequence_name = 'mensajes';
        SELECT next_val INTO next_id FROM mid_seq WHERE sequence_name = 'mensajes';
        RETURN next_id;
    END //
    DELIMITER ;
    
    -- 修改子类表的ID字段默认值
    ALTER TABLE resenia MODIFY COLUMN id BIGINT DEFAULT get_next_mensajes_id();
    ALTER TABLE post MODIFY COLUMN id BIGINT DEFAULT get_next_mensajes_id();
    

    之后即可直接省略id字段插入:

    insert into resenia(fecha, cont, rating) values ("01/01/2000", "BUU", 2);
    

二、是否需要改用@MappedSuperClass?

不需要,除非你不需要将Mensajes作为独立实体类使用:

  • @MappedSuperClass仅用于定义子类的映射模板,父类本身不会生成数据库表,而当前的TABLE_PER_CLASS策略允许父类作为独立实体被查询操作,更符合项目需求。
  • 即使改用@MappedSuperClass,手动SQL插入时的ID生成问题依然存在,还是需要维护序列或设置默认值,无法从根本上解决当前问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 19:53:17