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

Spring Boot 3.5.0中JPA查询返回实体的枚举字段为null,原生与非原生查询均异常

Spring Boot 3.5.0中JPA查询返回实体的枚举字段为null,原生与非原生查询均异常

我来帮你梳理下这个问题的核心原因和解决方案,你遇到的情况大概率是依赖版本冲突+多数据源配置不匹配的双重问题,再结合Spring Boot从2.x升级到3.x的兼容性细节,我们一步步解决:

一、先搞定最紧急的:Hibernate依赖冲突

你当前的Gradle依赖里藏着一个致命问题——手动引入了和Spring Boot 3.5.0不兼容的Hibernate版本:

  • Spring Boot 3.5.0属于Jakarta EE 9+生态,默认依赖Hibernate ORM 6.4.x
  • 你手动加的hibernate-entitymanager:5.6.14.Final是Hibernate 5.x的组件,在Hibernate 6.x里这个模块已经被合并到hibernate-core里了,完全不需要单独引入
  • 同时你还指定了hibernate-core:6.1.6.Final,比Spring Boot默认的版本旧,这会导致类加载混乱(比如你之前碰到的ClassNotFoundException),直接破坏JPA的枚举映射、实体转换逻辑

立刻修正的方法:删掉手动添加的Hibernate依赖,让Spring Boot的自动依赖管理来处理:

// 移除这两行旧依赖
// implementation 'org.hibernate:hibernate-core:6.1.6.Final'
// implementation 'org.hibernate:hibernate-entitymanager:5.6.14.Final'

// 只保留Spring Boot提供的starter即可,它会自动引入兼容的Hibernate版本
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springbootVersion"

二、修正JPA查询的写法(解决查不到/枚举null的问题)

1. 优先用非原生JPQL或派生查询

你之前的非原生查询写法有个小问题,like %:name%的JPQL语法需要用CONCAT来拼接,或者直接用Spring Data JPA的派生查询(更省心,还不容易错):

public interface BrandRepo extends JpaRepository<Brand, String> {
    // 方案1:正确的JPQL查询
    @Query("select i from Brand i where i.name like CONCAT('%', :name, '%') and i.reviewStage = :stage")
    List<Brand> findByNameContainingAndReviewStage(@Param("name") String name, @Param("stage") ReviewStage stage, Pageable pageable);

    // 方案2:更简洁的派生查询(推荐,Spring Data自动生成SQL)
    List<Brand> findByNameContainingAndReviewStage(String name, ReviewStage stage, Pageable pageable);
}

派生查询完全不需要自己写SQL/JPQL,Spring Data会自动处理枚举的参数绑定,不会出现查不到数据的情况。

2. 原生查询的枚举映射修正

如果你必须用原生查询,要注意JPA不会自动帮你把数据库的字符串转成枚举(非原生查询会自动处理),所以需要手动传入枚举的name(),同时确保查询结果的枚举字段能被正确映射:

@Query(value = "select * from brand where name like CONCAT('%', :name, '%') and review_stage = :stage", 
       nativeQuery = true)
List<Brand> findByNameLikeAndReviewStageNative(@Param("name") String name, 
                                              @Param("stage") String stage, 
                                              Pageable pageable);
// 调用的时候传入枚举的name():
// brandRepo.findByNameLikeAndReviewStageNative("test", stage.name(), pageable);

三、多数据源配置的关键检查

你提到项目是多数据源,这很可能是枚举字段返回null的核心原因——Brand实体和Repo可能没有绑定到正确的EntityManagerFactory:

  1. 实体与Repo的包扫描:确保@EnableJpaRepositories的basePackages包含BrandRepo的路径,@EntityScan包含Brand实体的路径,并且和对应数据源绑定:
@Configuration
@EnableJpaRepositories(
        basePackages = "com.your.project.repository.brand", // 你的BrandRepo所在包
        entityManagerFactoryRef = "brandEntityManagerFactory", // 对应数据源的EntityManagerFactory
        transactionManagerRef = "brandTransactionManager"
)
@EntityScan(basePackages = "com.your.project.entity.brand") // Brand实体所在包
public class BrandDataSourceConfig {
    // 数据源、EntityManagerFactory、TransactionManager的配置...
}
  1. EntityManager的枚举映射配置:在构建EntityManagerFactory时,明确指定枚举的编码策略,确保和实体的@Enumerated(EnumType.STRING)一致:
@Bean
public LocalContainerEntityManagerFactoryBean brandEntityManagerFactory(EntityManagerFactoryBuilder builder, DataSource brandDataSource) {
    Map<String, Object> jpaProps = new HashMap<>();
    // 强制枚举按字符串映射,和实体注解匹配
    jpaProps.put("hibernate.type.enum.encoding", "STRING");
    return builder
            .dataSource(brandDataSource)
            .packages("com.your.project.entity.brand")
            .persistenceUnit("brandPU")
            .properties(jpaProps)
            .build();
}

四、最后验证数据库枚举值的一致性

虽然你说数据库里的字段有值,但还是要确认:数据库中resource_type和review_stage的字符串值,和Java枚举的name()完全一致(大小写、拼写、下划线都不能错)。比如Java里的ReviewStage.CONFIRM_APPEALED,数据库里必须是CONFIRM_APPEALED,不能有空格或者拼写错误。

总结

按这个顺序排查:

  1. 先修复依赖冲突,这是所有诡异问题的根源
  2. 换成派生查询或正确的JPQL查询,避免原生查询的映射坑
  3. 检查多数据源的绑定,确保Brand实体和Repo用的是正确的EntityManager
  4. 验证数据库枚举值和Java枚举的一致性

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 10:00:30