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

Spring Boot 3.1.x中columnDefinition重复执行:是Bug还是设计?

Spring Boot 3.1.1中@Column columnDefinition重复执行导致DDL语法错误问题

问题场景

定义包含columnDefinition属性的JPA实体类后,首次运行能正常创建表;但未修改任何代码进行第二次运行时,系统尝试执行错误的ALTER语句,因语法错误失败。该问题仅出现在Spring Boot 3.1.1版本,Spring Boot 3.0.x及2.6.x版本无此异常。

实体类代码

@Entity
@Table(name = "simple_user")
public class SimpleUser {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(columnDefinition = "varchar(64) NOT NULL default 'John'")
    private String nickname;
}

首次运行成功建表的SQL日志

2023-06-24 18:22:20.380 | INFO  | restartedMain | p6spy | 21 ms | statement | create table simple_user (id serial not null, nickname varchar(64) NOT NULL default 'John', primary key (id)) | logSQL(Slf4JLogger.java:60)
2023-06-24 18:22:20.383 | INFO  | restartedMain | p6spy | 2 ms | statement | comment on table simple_user is 'User' | logSQL(Slf4JLogger.java:60)
2023-06-24 18:22:20.387 | INFO  | restartedMain | p6spy | 2 ms | statement | comment on column simple_user.nickname is 'nickname' | logSQL(Slf4JLogger.java:60)

第二次运行的错误日志

2023-06-24 18:25:25.520 | INFO  | restartedMain | c.z.h.HikariDataSource | HikariPool-1 - Start completed. | getConnection(HikariDataSource.java:123)
2023-06-24 18:25:26.079 | INFO  | restartedMain | p6spy | 22 ms | statement | select * from information_schema.sequences | logSQL(Slf4JLogger.java:60)
2023-06-24 18:25:26.106 | INFO  | restartedMain | o.h.b.i.BytecodeProviderInitiator | HHH000021: Bytecode provider name : bytebuddy | buildBytecodeProvider(BytecodeProviderInitiator.java:53)
2023-06-24 18:25:27.239 | INFO  | restartedMain | o.h.e.t.j.p.i.JtaPlatformInitiator | HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] | initiateService(JtaPlatformInitiator.java:51)
2023-06-24 18:25:27.272 | INFO  | restartedMain | p6spy | 3 ms | statement | select * from information_schema.sequences | logSQL(Slf4JLogger.java:60)
2023-06-24 18:25:27.315 | INFO  | restartedMain | p6spy | 5 ms | statement | alter table if exists simple_user alter column nickname set data type varchar(64) NOT NULL default 'John' | logSQL(Slf4JLogger.java:60)
2023-06-24 18:25:27.317 | WARN  | restartedMain | o.h.t.s.i.ExceptionHandlerLoggedImpl | GenerationTarget encountered exception accepting command : Error executing DDL "alter table if exists simple_user alter column nickname set data type varchar(64) NOT NULL default 'John'" via JDBC [ERROR: syntax error at or near "NOT"
  Position: 83] | handleException(ExceptionHandlerLoggedImpl.java:27)
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table if exists simple_user alter column nickname set data type varchar(64) NOT NULL default 'John'" via JDBC [ERROR: syntax error at or near "NOT"
  Position: 83]
        at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:92)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:574)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:514)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.migrateTable(AbstractSchemaMigrator.java:333)
        at org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl.performTablesMigration(GroupedSchemaMigratorImpl.java:84)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.performMigration(AbstractSchemaMigrator.java:232)
        at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.doMigration(AbstractSchemaMigrator.java:117)

问题分析与解决方案

是Bug还是设计?

这是Spring Boot 3.1.1(对应Hibernate版本升级)引入的Bug。原因是Hibernate在对比数据库元数据与实体定义时,错误地将columnDefinition中的约束(NOT NULL、default)包含到ALTER TABLE的set data type语句中,而标准SQL(尤其是PostgreSQL)修改数据类型的语法不允许在类型后直接附加约束,最终导致语法错误。旧版本Hibernate不会生成这类错误的ALTER语句。

如何禁止columnDefinition重复执行?

有以下几种可行方案:

  1. 调整DDL自动更新策略

    • 将spring.jpa.hibernate.ddl-auto设置为none或validate,关闭自动DDL修改能力(适合生产环境):
      spring.jpa.hibernate.ddl-auto=none
      
    • 若需保留首次自动建表能力,可在表创建完成后改为validate,仅验证结构不执行修改。
  2. 拆分columnDefinition为JPA标准属性

    • 避免在columnDefinition中混合写约束,改用JPA标准注解属性替代:
      // 拆分约束为标准属性
      @Column(length = 64, nullable = false, columnDefinition = "varchar(64) default 'John'")
      // 进一步拆分默认值(JPA 2.1+支持@ColumnDefault)
      @Column(length = 64, nullable = false)
      @ColumnDefault("'John'")
      private String nickname;
      

    这种方式让Hibernate能正确识别约束,不会生成错误的ALTER语句。

  3. 升级Spring Boot版本

    • 该问题已在Spring Boot 3.1.2及后续版本中修复,直接升级版本即可解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 10:50:06