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

Hibernate查询PostgreSQL JSON结果映射DTO报JDBC type 1111错误如何解决

错误原因说明

报错org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111是因为PostgreSQL返回的json_agg结果是JSON类型,对应JDBC的未定义类型1111,默认Hibernate没有配置该类型到Java集合的映射规则。

注意:尽量不要使用System作为自定义类/接口名,会和JDK内置的java.lang.System冲突,容易引发编译或运行异常,建议改为自定义名称如SystemDTO。

解决方案

方案1:SQL层面转字符串+接口投影默认方法反序列化(最简单,无需额外配置)

首先修改原生SQL,将json结果转为text字符串:

@Query(value = "SELECT category, " +
 " json_agg(json_build_object('id', id, 'name', name))::text as role " +
 "FROM table " +
 "GROUP BY category;", nativeQuery = true)
Collection<SystemProjection> getSystem();

调整投影接口,增加默认方法做JSON反序列化,引入Jackson的ObjectMapper即可:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;

public interface SystemProjection {
  String getCategory();
  String getRole(); // 先接收字符串类型的JSON

  // 默认方法反序列化为Role集合
  default List<Role> getRoleList() {
    ObjectMapper objectMapper = new ObjectMapper();
    try {
      return objectMapper.readValue(getRole(), new TypeReference<List<Role>>() {});
    } catch (Exception e) {
      throw new RuntimeException("JSON反序列化失败", e);
    }
  }

  interface Role {
    Long getId();
    String getName();
  }
}

调用的时候直接用getRoleList()方法就能拿到转换后的Role集合。

方案2:注册JSON类型到Hibernate方言(适合全局统一处理)

如果项目中大量用到PostgreSQL的JSON类型,可以自定义方言注册JSON映射:

  1. 自定义PostgreSQL方言类:
import org.hibernate.dialect.PostgreSQLDialect;

public class CustomPostgreSQLDialect extends PostgreSQLDialect {
  public CustomPostgreSQLDialect() {
    super();
    // 注册JDBC Type 1111对应JSON类型映射
    this.registerColumnType(java.sql.Types.OTHER, "json");
    this.registerColumnType(java.sql.Types.OTHER, "jsonb");
  }
}
  1. 配置文件中指定使用自定义方言,以Spring Boot为例,在application.yml中配置:
spring:
  jpa:
    properties:
      hibernate:
        dialect: 你的包名.CustomPostgreSQLDialect
  1. 如果你用的是Hibernate 6+,可以直接在投影上用@JdbcTypeCode(SqlTypes.JSON)注解标注role字段即可自动映射为List。

方案3:使用Tuple接收结果手动转换

如果不想修改方言也不想改SQL,可以直接用Tuple接收查询结果,再手动转换为DTO:

@Query(value = "SELECT category, " +
 " json_agg(json_build_object('id', id, 'name', name)) as role " +
 "FROM table " +
 "GROUP BY category;", nativeQuery = true)
Collection<Tuple> getSystemRaw();

转换逻辑:

ObjectMapper objectMapper = new ObjectMapper();
List<SystemDTO> systemList = getSystemRaw().stream().map(tuple -> {
  SystemDTO dto = new SystemDTO();
  dto.setCategory(tuple.get("category", String.class));
  String roleJson = tuple.get("role").toString();
  try {
    dto.setRole(objectMapper.readValue(roleJson, new TypeReference<List<RoleDTO>>() {}));
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
  return dto;
}).toList();

对应的DTO类定义:

import lombok.Data;
import java.util.List;

@Data
public class SystemDTO {
  private String category;
  private List<RoleDTO> role;
}

@Data
public class RoleDTO {
  private Long id;
  private String name;
}

内容的提问来源于stack exchange,提问作者Дмитрий Велигор

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 10:36:04