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
);
这项工作没有错误,但希望使用 fromDate 和 toDate
运行注意:
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:无法创建表
将 PostgreSQL JSON 列映射到 Hibernate 实体属性
休眠,PostgreSQL:无法提取结果集,SQLState 25P02