使用Postgres JSONB查询与Spring Data和绑定参数失败,InvalidDataAccessApiUsageException

时间:2017-12-14 06:05:13

标签: spring postgresql hibernate spring-data-jpa jsonb

我目前正在寻找异常的解决方案

org.springframework.dao.InvalidDataAccessApiUsageException: Parameter with that position [1] did not exist;

我当前的@Query注释是:

@Query(
    nativeQuery = true, 
    value = "SELECT * FROM thgcop_order_placement WHERE \"order_info\" @> '{\"parentOrderNumber\":\" :param \"}'")

我猜position [1] did not exist来自双引号加双引号加单引号。

我该如何做到这一点?

查询使用的是Postgres JSONB数据类型。列定义为ORDER_INFO JSONB

以下本机查询在Postgres客户端中运行良好:

SELECT * FROM thgcop_order_placement
WHERE "order_info" @> '{"parentOrderNumber":"ORD123"}'

4 个答案:

答案 0 :(得分:5)

除了下面的内容之外,以上所有内容都没有,

服务层代码: -

OrderInfo orderInfo = new OrderInfo();
orderInfo.setParentOrderNumber("ORD123");
....
String param = objectMapper.writeValueAsString(orderInfo);
List<Order> list = jpaRepository.getByParentOrderNumber(param);

JpaRepository.java代码: -

@Query(nativeQuery = true, value = "select * from thgcop_order_placement where order_info @> CAST(:condition as jsonb)")
List<Order> getByParentOrderNumber(@Param("condition") String parentOrderNumber);

这就是我实现结果的方式。我希望这对所有热心的 !!

非常有帮助
  

谢谢大家的帮助!!!

答案 1 :(得分:0)

尝试按以下方式绑定参数

@Query(nativeQuery = true, value = "SELECT * FROM thgcop_order_placement"
  + " WHERE \"order_info\" @> '{\"parentOrderNumber\":\" ?1 \"}'")

答案 2 :(得分:0)

TL; DR :首先使用Bind Parameter和普通JDBC。然后转到Spring Data,可能会回到自定义实现上。

你在这里面临许多层面的问题。

  1. 让我们暂时忽略Spring Data。 您展示的语句与您尝试使用Spring Data构建的语句非常不同,因为它不包含绑定变量。 而不是

    SELECT * FROM thgcop_order_placement WHERE "order_info" @> '{"parentOrderNumber":"ORD123"}'
    

    我们应该将它与

    进行比较
    SELECT * FROM thgcop_order_placement WHERE "order_info" @> '{"parentOrderNumber": ? }'
    

    请注意,我们正在丢失引号,因为它们表示文字字符串但我们不提供文字字符串而是绑定参数。

  2. 我还没有发现任何迹象表明你可以在JSON表达式的部分中使用绑定参数。因此,我们需要使用:

    而不是上述声明
    SELECT * FROM thgcop_order_placement WHERE "order_info" @> ?
    

    当然,bind参数应该包含完整的JSON表达式

  3. 不幸的是,这似乎不起作用,因为现在Postgres认为绑定参数是VARCHAR而不是JSON表达式。见https://blog.2ndquadrant.com/processing-json/。我认为正确的版本应该是

    SELECT * FROM thgcop_order_placement WHERE "order_info" @> ?::json
    

    但是,我也无法使用它。

  4. 在任何情况下,您都可以将参数转换为JSON结构。 通常我建议使用SpEL表达式。但它不起作用,因为Spring Data在SpEL表达式中需要花括号并将它们视为SpEL表达式的结束。

  5. 如果您使用简单的JDBC连接或JdbcTemplate获得此类内容,则可以开始考虑@Query注释。

    @Query(
        value= "SELECT * FROM thgcop_order_placement WHERE \"order_info @> :name::json",
        nativeQuery = true)
    
  6. 这可能会引发更多问题,因为Spring Data会考虑参数名称的::json部分。如果是这种情况,您将不得不依赖自定义实施。

    I ran a couple of experiments, which you can look at and play with here.

答案 3 :(得分:0)

我也被困在同一个问题上一段时间。似乎springboot在解析以字符串格式存在的查询时搞砸了。但是,这是我找到的解决方案,可以直接在存储库中作为本机查询使用:

  • 由于order_info的类型为jsonb,因此可以将搜索到的值转换为jsonb值。
  • 要搜索的值:{"parentOrderNumber":"ORD123"}
  • 让我们转义整个要由Java解析的字符串。
  • String searchString = "{\"parentOrderNumber\":\"ORD123\"}"
  • 现在,让我们以spring可以理解的方式键入postgres查询。
@Query(
value = "SELECT * from thgcop_order_placement where ((?1\\:\\:jsonb) <@ (order_info\\:\\:jsonb))",
nativeQuery=true
)
List<Order> getByParentOrderNumber(String searchString);

在哪里

  • 如上所述,Spring会将?1替换为searchString的值。
  • ::是类型转换运算符,使用它我们将传递的参数(searchString)显式转换为jsonb。因此,在尝试进行搜索之前,值{\"parentOrderNumber\":\"ORD123\"}被转换为jsonb
  • 还将列order_info的值显式类型转换为jsonb
  • 现在,当两个项目(要搜索的值和列)都是相同的数据类型时,我们可以使用<@运算符检查列值中是否包含搜索字符串。

在服务级别,我们只需要这样做:

String orderNumber = "-- some order value e.g. ORD123 --"
String searchString = "{\"parentOrderNumber\":\"" + orderNumber + "\"}"
List<Order> list = jpaRepository.getByParentOrderNumber(searchString);

有关Postgres JSON运算符的更多详细信息,可以在以下官方文档中找到:https://www.postgresql.org/docs/9.5/functions-json.html