如何在Hibernate中处理原生Native Query返回的JSON类型值?
问题原因
报错No Dialect mapping for JDBC type: 1111是因为PostgreSQL返回的JSON/JSONB类型属于JDBC的OTHER类型(对应编码1111),Hibernate默认的PostgreSQL方言没有对该类型做映射配置,因此无法直接转换为Java对象。
可行方案
方案1:扩展PostgreSQL方言,全局注册JSON类型映射
该方案全局生效,后续所有JSON类型返回都无需额外配置。
- 自定义方言类,继承你当前使用的PostgreSQL方言,注册JSON类型映射:
import org.hibernate.dialect.PostgreSQL10Dialect; import com.vladmihalcea.hibernate.type.json.JsonNodeBinaryType; import java.sql.Types; public class CustomPostgreSQLDialect extends PostgreSQL10Dialect { public CustomPostgreSQLDialect() { super(); // 映射JSONB类型到Jackson的JsonNode,如需映射普通JSON替换为JsonNodeStringType.class.getName() this.registerHibernateType(Types.OTHER, JsonNodeBinaryType.class.getName()); } }
- 在项目配置文件中修改Hibernate方言指向自定义类:
# application.yml 配置示例 spring: jpa: properties: hibernate: dialect: com.yourproject.config.CustomPostgreSQLDialect
方案2:使用注解显式指定字段JSON类型
如果不需要全局配置,可直接在对应返回类的字段上指定类型映射:
- 引入对应版本的
hibernate-types依赖,在返回字段上添加@Type注解:
import com.vladmihalcea.hibernate.type.json.JsonType; import org.hibernate.annotations.Type; import com.fasterxml.jackson.databind.JsonNode; // DTO或实体类示例 public class FieldDetailDTO { private Long mapDetailsId; private Integer rowId; @Type(JsonType.class) private JsonNode data; // 省略构造方法、getter、setter }
- 如果你使用Hibernate 6及以上版本,无需额外引入依赖,直接使用官方自带的JSON类型注解即可:
import jakarta.persistence.Column; import org.hibernate.type.SqlTypes; import org.hibernate.annotations.JdbcTypeCode; import com.fasterxml.jackson.databind.JsonNode; public class FieldDetailDTO { private Long mapDetailsId; private Integer rowId; @JdbcTypeCode(SqlTypes.JSON) private JsonNode data; // 省略构造方法、getter、setter }
方案3:通过SqlResultSetMapping指定查询结果映射
如果是使用原生查询返回自定义DTO,可通过@SqlResultSetMapping显式指定JSON列的类型:
import com.vladmihalcea.hibernate.type.json.JsonType; import jakarta.persistence.SqlResultSetMapping; import jakarta.persistence.ConstructorResult; import jakarta.persistence.ColumnResult; @SqlResultSetMapping( name = "FieldDetailMapping", classes = @ConstructorResult( targetClass = FieldDetailDTO.class, columns = { @ColumnResult(name = "map_details_id", type = Long.class), @ColumnResult(name = "row_id", type = Integer.class), @ColumnResult(name = "data", type = JsonType.class) } ) )
Repository层查询指定映射即可:
@Query(value = "SELECT map_details_id,row_id,json_object_agg(key, value) AS data FROM field_details_tbl where map_details_id=:mapId GROUP BY row_id,map_details_id ORDER BY row_id", nativeQuery = true, resultSetMapping = "FieldDetailMapping") List<FieldDetailDTO> getFieldDetails(@Param("mapId") Long mapId);
内容的提问来源于stack exchange,提问作者maverick cj
相关产品推荐
相关产品推荐

