Hibernate的Postgresql`无法确定参数的数据类型`

Posted

技术标签:

【中文标题】Hibernate的Postgresql`无法确定参数的数据类型`【英文标题】:Postgres Sql `could not determine data type of parameter` by Hibernate 【发布时间】:2019-09-29 01:25:48 【问题描述】:

我有 JpaRepository

@Repository
public interface CardReaderRepository extends JpaRepository<CardReaderEntity, Integer > 



当我在这个 repo 中执行与此相同的查询时:

@Query(
    value = "SELECT new ir.server.component.panel.response." +
            "InvalidCardReaderDataDigestResponse(" +
            "    cr.driverNumber, cr.exploiterCode, cr.lineCode, " +
            "    cr.transactionDate, cr.offLoadingDate, " +
            "    cr.cardReaderNumber, " +
            "    sum(cr.count) , sum(cr.remind) " +
            ") " +
            "FROM CardReaderEntity cr " +
            "WHERE cr.company.id = :companyId " +
            "AND cr.status.id in :statusIds " +
            "AND cr.deleted = false " +
            "AND  (:fromDate is null or cr.offLoadingDate >= :fromDate ) " +
            "AND  (:toDate   is null or cr.offLoadingDate <= :toDate   ) " +
            "group by cr.driverNumber, cr.exploiterCode, cr.lineCode, cr.transactionDate, cr.offLoadingDate, cr.cardReaderNumber"
)
Page<InvalidCardReaderDataDigestResponse> findAllInvalidCardReaderDataDigestByCompanyIdAndStatusIdIn(
        @Param( "companyId" )   int companyId,
        @Param( "fromDate" )    Date fromDate,
        @Param( "toDate" )      Date toDate,
        @Param( "statusIds" )   List<Integer> statusIds,
        Pageable pageable
);

错误是:

org.postgresql.util.PSQLException: ERROR: could not determine data type of parameter $3
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433) ~[postgresql-42.2.2.jar:42.2.2]
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178) ~[postgresql-42.2.2.jar:42.2.2]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306) ~[postgresql-42.2.2.jar:42.2.2]

但是当查询更改为:

@Query(
    value = "SELECT new ir.server.component.panel.response." +
            "InvalidCardReaderDataDigestResponse(" +
            "    cr.driverNumber, cr.exploiterCode, cr.lineCode, " +
            "    cr.transactionDate, cr.offLoadingDate, " +
            "    cr.cardReaderNumber, " +
            "    sum(cr.count) , sum(cr.remind) " +
            ") " +
            "FROM CardReaderEntity cr " +
            "WHERE cr.company.id = :companyId " +
            "AND cr.status.id in :statusIds " +
            "AND cr.deleted = false " +
            "AND  (:fromDate is null ) " +
            "AND  (:toDate   is null ) " +
            "group by cr.driverNumber, cr.exploiterCode, cr.lineCode, cr.transactionDate, cr.offLoadingDate, cr.cardReaderNumber"
)
Page<InvalidCardReaderDataDigestResponse> findAllInvalidCardReaderDataDigestByCompanyIdAndStatusIdIn(
        @Param( "companyId" )   int companyId,
        @Param( "fromDate" )    Date fromDate,
        @Param( "toDate" )      Date toDate,
        @Param( "statusIds" )   List<Integer> statusIds,
        Pageable pageable
);

这项工作没有错误,但希望使用 fromDatetoDate

运行

注意:

CardReaderEntity中的

offLoadingDate

@Basic
@Temporal( TemporalType.TIMESTAMP )
public Date getOffLoadingDate() 
    return offLoadingDate;

public void setOffLoadingDate(Date offLoadingDate) 
    this.offLoadingDate = offLoadingDate;

我的 java 文件中的所有日期导入都是 java.util.Date

【问题讨论】:

能分享一下date参数的格式吗?是 YYYY/MM/DD 吗?数据库上的格式是哪一种? @CarlosAlvesJorge 我已经在我的问题中解释过,这是 TIMSTAMP 格式。 如果你想避免 Postgres 的可空性问题,你必须删除注解,并手动实现这个功能***.com/a/53649111/3841161 【参考方案1】:

PostgreSQL 驱动程序试图找出参数的类型,以将这些参数直接告知 PostgreSQL 服务器。这是 PostgreSQL 服务器能够比较字段所必需的。在 java.sql.Timestamp 的情况下,PostgreSQL 驱动程序无法执行此操作,因为 PostgreSQL 有两个匹配字段。一方面是时间戳,另一方面是带有时区信息的 timestamptz。结果是,PostgreSQL 驱动程序只会将其与 Oid.UNSPECIFIED 匹配。这种行为大多数时候不是问题,因为 PostgreSQL 服务器能够检测到该类型。在 PostgreSQL 驱动类 PgPreparedStatement 中有对此问题的详细描述。

因此,您可以做的是仅在 Postgres 无法检测到正确类型(当您检查 null 时)时强制转换为时间戳/日期类型。 所以不是

(:fromDate is null )

使用

(cast(:fromDate as date) is null )

toDate 相同

【讨论】:

【参考方案2】:

根据我的经验,您必须先为外部值分配一个类型,然后才能让 postres 检查它是否为空。例如,此代码不适用于 postgres:

SELECT * FROM table WHERE $1 IS NULL OR column = $1;

什么会起作用:

SELECT * FROM table WHERE $1::text IS NULL OR column = $1::text;

您可以尝试将正确的类型应用于您的变量,看看它是否有效。在您的示例中,您应该尝试

@Query(
    value = "SELECT new ir.server.component.panel.response." +
            "InvalidCardReaderDataDigestResponse(" +
            "    cr.driverNumber, cr.exploiterCode, cr.lineCode, " +
            "    cr.transactionDate, cr.offLoadingDate, " +
            "    cr.cardReaderNumber, " +
            "    sum(cr.count) , sum(cr.remind) " +
            ") " +
            "FROM CardReaderEntity cr " +
            "WHERE cr.company.id = :companyId " +
            "AND cr.status.id in :statusIds " +
            "AND cr.deleted = false " +
            "AND  (:fromDate::timestamp is null or cr.offLoadingDate >= :fromDate::timestamp ) " +
            "AND  (:toDate::timestamp   is null or cr.offLoadingDate <= :toDate::timestamp   ) " +
            "group by cr.driverNumber, cr.exploiterCode, cr.lineCode, cr.transactionDate, cr.offLoadingDate, cr.cardReaderNumber"
)

事实上,postgres 在大多数情况下不会要求类型,检查空值是需要类型的特殊情况之一。

【讨论】:

@PowR 提供的版本可以正常工作,但这种语法似乎不行。我得到一个QuerySyntaxException: unexpected token 但是我只尝试了:fromDate::timestamp 版本。它可能仍然适用于$3::timestamp @DávidLeblay 是的,使用 $x 始终是避免错误的更好主意。

以上是关于Hibernate的Postgresql`无法确定参数的数据类型`的主要内容,如果未能解决你的问题,请参考以下文章

Play + JPA + Hibernate + PostgreSQL:无法创建表

Hibernate 支持 Postgresql UUID?

将 PostgreSQL JSON 列映射到 Hibernate 实体属性

休眠,PostgreSQL:无法提取结果集,SQLState 25P02

错误:无法从“10.3”确定 PostgreSQL 版本 - Heroku 上的 Django

错误:无法从“10.4”确定 PostgreSQL 版本