使用弹簧数据的Postgres JSONB查询和绑定参数将失败,而无效的DATAACCESSAPIUSAGEEXCEPT



我当前正在寻找一个解决方案

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来自双引号加上双引号加单Quote。

我该如何使这项工作?

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

以下本机查询在Postgres客户端中工作正常:

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

以上除了下面的我都不适用于我,

服务层代码: -

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);

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

都会有所帮助

谢谢大家的帮助!

tl; dr :首先使其与bind参数和普通JDBC一起使用。然后转到Spring数据,可能会倒在自定义实现上。

您在这里在许多层面上都面临问题。

  1. 让我们从现在忽略春季数据开始。您显示的语句与您尝试使用弹簧数据构建的语句非常不同,因为它不包含绑定变量。所以而不是

    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" @> ?
    

    当然,绑定参数应包含完整的JSON表达式

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

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

    ,但我也无法工作。

  4. 在任何情况下,您都可以将参数转换为JSON结构。通常,我建议对此使用SPEL表达式。但这行不通,因为弹簧数据会扼杀Spel表达中所需的卷曲括号,并将其视为Spel表达式的末端。

  5. 如果您得到这样的东西可以使用简单的JDBC连接或JdbcTemplate工作,则可以开始考虑@Query注释。

    @Query(
        value= "SELECT * FROM thgcop_order_placement WHERE "order_info @> :name::json",
        nativeQuery = true)
    

这可能会触发更多问题,因为春季数据将考虑参数名称的::json部分。如果是这种情况,您必须退回自定义实现。

我进行了几个实验,您可以在这里查看和玩耍。

尝试绑定参数如下

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

我也陷入了一段时间。似乎Springboot以字符串格式解析查询时弄乱了。但是,这是我发现的解决方案,该解决方案将直接用作存储库中的本机查询:

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

在哪里,

  • Spring将用searchString的值代替?1,如上所述。
  • ::是使用的类型运算符,我们明确将传递的参数(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

最新更新