非ID列用@GeneratedValue生成值始终为null,自定义生成器未触发
非ID列自定义序列生成器未触发问题排查与解决
问题情况
尝试为实体的非ID列ss_request_number生成REQ00000001格式的自增序列号,使用@GeneratedValue配合自定义ReqSequenceGenerator实现,但该字段值始终为null,自定义生成器完全未被调用。当前使用H2数据库,疑惑是否需要为该列设置特定约束。
问题原因
- Hibernate默认行为限制:
@GeneratedValue注解默认仅对@Id标记的主键列生效,非ID列不会自动触发生成逻辑。 - 数据库类型冲突:实体类中
@Column的columnDefinition = "serial"配置,会让H2数据库自动为该列生成数值型自增值,覆盖了自定义生成器的执行逻辑。 - 缺少生成标记:未添加
@Generated注解告知Hibernate该字段值由框架生成,而非应用程序手动赋值。
解决方案
- 移除冲突的数据库类型配置:删除
@Column中的columnDefinition = "serial",避免数据库自动生成逻辑干扰自定义生成器。 - 添加生成时机注解:为非ID列添加
@Generated(GenerationTime.INSERT),标记该字段在插入数据时由Hibernate自动生成。 - 确保序列配置正确:可手动在Liquibase中创建对应序列(可选,Hibernate也会自动创建),保证自定义生成器能获取到自增序列值。
修正后代码示例
实体类代码
import org.hibernate.annotations.Parameter; import org.hibernate.annotations.*; import javax.persistence.*; import java.util.UUID; @Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name = "ss_request", schema = "AGENCY_SS_APP") public class SSRequest { private static final long serialVersionUID = 1L; // ID列,生成正常 @Id @GeneratedValue(strategy = GenerationType.AUTO) @Schema(description = "ss_requestid") @Column(name = "ss_request_id", nullable = false, updatable = false, length = 36) @Type(type = "uuid-char") private UUID ssRequestId; // 修正后的自增序列列 @Column(name="ss_request_number", updatable = false, nullable = false, length = 20) @Schema(description ="Request Number") @Generated(GenerationTime.INSERT) // 标记插入时生成字段值 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "request_seq") @GenericGenerator( name = "request_seq", strategy = "com.vermontmutual.agencyssportal.util.ReqSequenceGenerator", parameters = { @Parameter(name = ReqSequenceGenerator.INCREMENT_PARAM, value = "1"), @Parameter(name = ReqSequenceGenerator.VALUE_PREFIX_PARAMETER, value = "REQ"), @Parameter(name = ReqSequenceGenerator.NUMBER_FORMAT_PARAMETER, value = "%08d") }) private String ssRequestNumber; }
Liquibase配置
<!-- 可选:手动创建序列,确保与生成器配置一致 --> <createSequence sequenceName="request_seq" startValue="1" incrementBy="1" schemaName="AGENCY_SS_APP"/> <column name="ss_request_number" type="VARCHAR(20)"> <constraints nullable="false" /> </column>
自定义生成器代码(无需修改)
package com.vermontmutual.agencyssportal.util; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.LongType; import org.hibernate.type.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.Properties; public class ReqSequenceGenerator extends SequenceStyleGenerator { Logger LOG = LoggerFactory.getLogger(ReqSequenceGenerator.class); public static final String VALUE_PREFIX_PARAMETER = "valuePrefix"; public static final String VALUE_PREFIX_DEFAULT = ""; private String valuePrefix; public static final String NUMBER_FORMAT_PARAMETER = "numberFormat"; public static final String NUMBER_FORMAT_DEFAULT = "%d"; private String numberFormat; @Override public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException { LOG.info("Inside generate of Request Number:"); return valuePrefix + String.format(numberFormat, super.generate(session, object)); } @Override public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { LOG.info("Inside configure of Request Number:"); super.configure(LongType.INSTANCE, params, serviceRegistry); valuePrefix = ConfigurationHelper.getString(VALUE_PREFIX_PARAMETER, params, VALUE_PREFIX_DEFAULT); numberFormat = ConfigurationHelper.getString(NUMBER_FORMAT_PARAMETER, params, NUMBER_FORMAT_DEFAULT); } }
内容的提问来源于stack exchange,提问作者Sharvari Nagesh
相关产品推荐
相关产品推荐

