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

在Hibernate 6.3中使用PostgreSQLEnumJdbcType的查询问题

问题解决:Spring Boot + Hibernate 原生查询中PostgreSQL枚举参数映射错误

问题场景

使用Spring Boot v3.2.0和Hibernate v6.3.1,实体类中枚举字段已通过@Enumerated(EnumType.STRING)和@JdbcType(PostgreSQLEnumJdbcType.class)映射为PostgreSQL的ENUM类型(request_statuses):

enum STATUS {
    DRAFT, NEW, IN_PROGRESS, COMPLETED, REJECTED;
}

@Enumerated(EnumType.STRING)
@Column(name = "status")
@JdbcType(PostgreSQLEnumJdbcType.class)
private STATUS status;

但在Repository的原生查询方法中传入枚举列表时报错:

@Query(nativeQuery = true, value = "SELECT * FROM requests r WHERE r.status IN (?1)")
List<Request> getRequestsByStatus(List<Request.STATUS> statuses);

错误信息:

Caused by: org.hibernate.exception.SQLGrammarException: JDBC exception executing SQL [SELECT * FROM requests r WHERE r.status IN (?,?,?,?,?)] [ERROR: operator does not exist: request_statuses = smallint

原因分析

Hibernate处理原生查询的枚举参数时,会调用createEnumType方法创建枚举类型映射,该方法默认使用TypeConfiguration的全局默认配置(通常为ORDINAL,即枚举的序号),不会读取实体字段上的@JdbcType或@Enumerated注解,导致参数被转为小整数类型,与PostgreSQL的ENUM类型不匹配。

解决方案

方案1:全局配置枚举默认映射为STRING

在application.properties中添加全局配置,强制Hibernate将枚举默认按字符串处理:

spring.jpa.properties.hibernate.type.preferred_enum_jdbc_type=STRING

或YAML格式:

spring:
  jpa:
    properties:
      hibernate:
        type:
          preferred_enum_jdbc_type: STRING

此方案最简单,适合所有枚举都需要按字符串映射的场景。

方案2:在查询中显式指定参数类型

通过Hibernate的@Parameter注解,给原生查询的参数指定对应的JdbcType:

import org.hibernate.type.descriptor.jdbc.PostgreSQLEnumJdbcType;
import org.hibernate.annotations.Parameter;

@Query(nativeQuery = true, value = "SELECT * FROM requests r WHERE r.status IN (?1)")
List<Request> getRequestsByStatus(
    @Parameter(name = "statuses", type = PostgreSQLEnumJdbcType.class) 
    List<Request.STATUS> statuses
);

该方案针对单个查询方法生效,适合局部调整的场景。

方案3:全局注册自定义枚举类型映射

创建自定义的EnumJavaType,强制返回字符串类型的JdbcType:

import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;

public class StringEnumJavaType<E extends Enum<E>> extends EnumJavaType<E> {
    public StringEnumJavaType(Class<E> enumClass) {
        super(enumClass);
    }

    @Override
    public JdbcType getRecommendedJdbcType(org.hibernate.type.descriptor.java.JdbcTypeIndicators indicators) {
        return VarcharJdbcType.INSTANCE;
    }
}

然后创建TypeContributor注册该类型:

import org.hibernate.boot.model.TypeContributions;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.TypeContributor;

public class StringEnumTypeContributor implements TypeContributor {
    @Override
    public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        typeContributions.contributeJavaType(EnumJavaType.class, (descriptor, scope) -> {
            Class<?> rawType = descriptor.getJavaType();
            if (Enum.class.isAssignableFrom(rawType) && rawType != Enum.class) {
                //noinspection unchecked
                return new StringEnumJavaType<>((Class<? extends Enum>) rawType);
            }
            return null;
        });
    }
}

最后在配置文件中指定TypeContributor:

spring.jpa.properties.hibernate.type_contributors=com.yourpackage.StringEnumTypeContributor

此方案适合需要对枚举映射做全局定制的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 11:07:03