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

H2数据库无法创建ScoreCard表的技术问题求助

Spring Boot + H2 无法创建ScoreCard表,抛出SQLGrammarException异常

问题现象

在Spring Boot项目中使用H2数据库时,ScoreCard表无法创建,抛出SQLGrammarException,核心错误提示找不到HIBERNATE_SEQUENCE序列。其他同结构的实体表可正常生成,仅该表出现问题。

相关代码与配置

ScoreCard实体类

@Entity
@Table(name = "SCORE_CARD")
public final class ScoreCard implements Serializable {

    public static final int DEFAULT_SCORE = 10;
    private static final long serialVersionUID = -2504167837465532618L;

    @Id
    @GeneratedValue
    @Column(name = "CARD_ID")
    private final Long cardId;

    @Column(name = "USER_ID")
    private final Long userId;

    @Column(name = "ATTEMPT_ID")
    private final Long attemptId;

    @Column(name = "SCORE_TS")
    private final Long scoreTimestamp;

    @Column(name = "SCORE")
    private final int score;

    @Column(name = "CORRECT")
    private final boolean correct;

    public ScoreCard(Long cardId, Long userId, Long attemptId, Long scoreTimestamp, int score,
                     boolean correct) {
        this.cardId = cardId;
        this.userId = userId;
        this.attemptId = attemptId;
        this.scoreTimestamp = scoreTimestamp;
        this.score = correct ? DEFAULT_SCORE : 0;
        this.correct = correct;
    }

    public ScoreCard() {
        this(null, null, null, null, 0, false);
    }

    public ScoreCard(Long userId, Long attemptId, boolean correct) {
        this(null, userId, attemptId, System.currentTimeMillis(), 0, correct);
    }

    public Long getCardId() {
        return cardId;
    }

    public Long getUserId() {
        return userId;
    }

    public Long getAttemptId() {
        return attemptId;
    }

    public Long getScoreTimestamp() {
        return scoreTimestamp;
    }

    public long getScore() {
        return score;
    }

    public boolean isCorrect() {
        return correct;
    }

}

application.properties配置

####### START H2 #######

# Creates the database in a file
spring.datasource.url=jdbc:h2:file:~/projects-data/social-multiplication/gamification;DB_CLOSE_ON_EXIT=FALSE

# Shows the SQL in console
spring.jpa.properties.hibernate.show_sql=true

spring.datasource.username=
spring.datasource.password=

####### END H2 #######

出错代码(GameServiceImpl.java 46-47行)

ScoreCard scoreCard = new ScoreCard(userId, attemptId, correct);
scoreCardRepository.save(scoreCard);

已尝试操作

将@GeneratedValue修改为@GeneratedValue(strategy = GenerationType.IDENTITY),问题仍未解决。


问题原因分析

  1. 实体字段为final修饰:JPA实体需要允许Hibernate通过反射为字段赋值(包括生成的主键ID),但ScoreCard中所有字段均为final,导致Hibernate无法将自增或序列生成的ID注入到cardId字段,同时DDL表生成逻辑也会受影响。
  2. 缺少DDL自动生成配置:application.properties中未配置spring.jpa.hibernate.ddl-auto,默认值为none,Hibernate不会自动创建新的实体表和序列,这也是新表ScoreCard无法生成的关键原因。

解决方案

1. 移除实体字段的final修饰符

修改ScoreCard类,去掉所有字段的final关键字,确保Hibernate能正常赋值:

@Entity
@Table(name = "SCORE_CARD")
public class ScoreCard implements Serializable { // 建议移除类的final修饰,避免潜在问题

    public static final int DEFAULT_SCORE = 10;
    private static final long serialVersionUID = -2504167837465532618L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "CARD_ID")
    private Long cardId;

    @Column(name = "USER_ID")
    private Long userId;

    @Column(name = "ATTEMPT_ID")
    private Long attemptId;

    @Column(name = "SCORE_TS")
    private Long scoreTimestamp;

    @Column(name = "SCORE")
    private int score;

    @Column(name = "CORRECT")
    private boolean correct;

    // 构造器、getter方法保持不变
}

2. 添加DDL自动生成配置

在application.properties中添加以下配置,根据环境选择合适的参数:

# 开发环境:每次启动创建表,关闭时删除
spring.jpa.hibernate.ddl-auto=create-drop

# 或者生产/测试环境:仅更新表结构(不会删除已有数据)
# spring.jpa.hibernate.ddl-auto=update

3. 确认ID生成策略

如果使用GenerationType.IDENTITY,H2会自动创建自增列,无需依赖序列;如果坚持使用SEQUENCE策略,添加ddl-auto配置后Hibernate会自动生成HIBERNATE_SEQUENCE序列。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 18:13:09