JPA执行PostgreSQL JSON数组两次CAST查询报错:无JDBC映射方言
问题分析与解决方案
核心问题拆解
你遇到的错误和写法问题主要集中在三个点:SQL拼写错误、JSON类型映射失败、类型转换写法优化。
1. 修复SQL拼写错误
JPA代码里的DISTINC是拼写错误,必须修正为DISTINCT,否则会直接触发SQL语法错误。
2. 解决「No dialect for Mapping JDBC 1111」错误
这个错误是因为PostgreSQL的JSON类型对应的JDBC类型代码为1111,JPA默认无法直接将其映射到你的ServiceDefinition实体类,有两种解决方式:
- 方案A:转字符串后手动反序列化
将查询中的d.data改为d.data::TEXT,把JSON转为字符串返回,之后在Java代码中用Jackson/Gson等工具反序列化为ServiceDefinition对象。 - 方案B:使用Hibernate JSON类型支持
如果你用Hibernate作为JPA实现,引入hibernate-types依赖,在实体类的data字段上标注JSON类型注解,让框架自动处理映射。
3. 类型转换写法优化
你写的CAST(CAST(e as text) as Integer)是有效的,但可以简化为PostgreSQL原生语法(e::TEXT)::INTEGER,或者标准SQL的CAST(e AS INTEGER),两种写法功能完全一致。
修正后的代码示例
方案A:字符串转实体实现
@Query( nativeQuery = true, value = "SELECT DISTINCT d.data::TEXT " + "FROM myScheme.myTable d, myScheme.mySecondTable g, " + "json_array_elements(d.data->>'categorys') e " + "WHERE d.id = :id AND d.data->>'categorys' IS NOT NULL " + "AND (e::TEXT)::INTEGER IN (g.id_product_category_magento) " + "AND (e::TEXT)::INTEGER IN (:categories)" ) List<String> getServiceDefinitionsAsJson(Set<Long> categories, @Param("id") Long id);
业务代码中反序列化:
ObjectMapper objectMapper = new ObjectMapper(); List<ServiceDefinition> definitions = getServiceDefinitionsAsJson(categories, id) .stream() .map(json -> objectMapper.readValue(json, ServiceDefinition.class)) .collect(Collectors.toList());
方案B:Hibernate JSON类型映射实现
首先引入Maven依赖(Hibernate 5.x版本):
<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>2.19.0</version> </dependency>
实体类字段添加注解:
@Column(columnDefinition = "JSON") @Type(type = "json") private ServiceDefinition data;
Hibernate 6+版本可改用:
@Column(columnDefinition = "JSON") @JdbcTypeCode(SqlTypes.JSON) private ServiceDefinition data;
修正后的JPA查询:
@Query( nativeQuery = true, value = "SELECT DISTINCT d.data " + "FROM myScheme.myTable d, myScheme.mySecondTable g, " + "json_array_elements(d.data->>'categorys') e " + "WHERE d.id = :id AND d.data->>'categorys' IS NOT NULL " + "AND (e::TEXT)::INTEGER IN (g.id_product_category_magento) " + "AND (e::TEXT)::INTEGER IN (:categories)" ) List<ServiceDefinition> yest(Set<Long> categories, @Param("id") Long id);
额外优化:改用显式JOIN提升可读性
原始隐式笛卡尔积写法可以改为显式JOIN,逻辑更清晰:
SELECT DISTINCT d.data FROM myScheme.myTable d CROSS JOIN json_array_elements(d.data->>'categorys') e JOIN myScheme.mySecondTable g ON (e::TEXT)::INTEGER = g.id_product_category_magento WHERE d.id = :id AND d.data->>'categorys' IS NOT NULL AND (e::TEXT)::INTEGER IN (:categories)
内容的提问来源于stack exchange,提问作者Eduardojls
相关产品推荐
相关产品推荐

