【问题标题】:JPA Native Query set null parameterJPA Native Query 设置空参数
【发布时间】:2021-11-13 03:22:20
【问题描述】:

这是我的代码部分:

Query q = em.createNativeQuery("insert into table_name (value_one, value_two, value_three) values (?,?,?)");
q.setParameter(1, value1);
q.setParameter(2, value2);
q.setParameter(3, value3);
q.executeUpdate();

value3 有时可以为空(日期类对象)。如果它为 null,则会引发以下异常:

  Caused by: org.postgresql.util.PSQLException: ERROR: column "value_three" is of type timestamp without time zone but expression is of type bytea
  Hint: You will need to rewrite or cast the expression.
  Position: 88
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:500)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:334)
    at org.hibernate.engine.query.NativeSQLQueryPlan.performExecuteUpdate(NativeSQLQueryPlan.java:189)
    ... 11 more

如何使这段代码正常工作并将空值保存到数据库中?

【问题讨论】:

  • 你的数据库是什么?可以直接执行查询吗?
  • 您是否在数据库中检查了该列是否实际上允许NULL?另外请检查entity中的字段是否标注@Column(nullable=true)?
  • PostgreSQL 9.2. 是的,我可以直接这样做:insert into table_name (value_one, value_two, value_three) values ('test', 'test', NULL);
  • 另外,你能用setTimestamp()代替setParameter()吗?
  • 很遗憾,javax.persistence.Query 没有这样的方法。是否可以将其转换为org.hibernate.Query,有这样的方法?

标签: java jpa


【解决方案1】:

您正在使用 postgresql(堆栈已经说明了这一点),并且可能是 Hibernate,并且几乎肯定会遇到这个问题:PostgreSQL JDBC Null String taken as a bytea

我使用了这个特殊的解决方案: https://stackoverflow.com/a/23501509/516188

这意味着转义到 Hibernate API,以便您可以给出表达式的类型。

在我的例子中,它是一个可以为空的 Short,所以我使用了:

.setParameter("short", shortValue, ShortType.INSTANCE);

shortValue 的类型为 Short。

【讨论】:

  • 无法解析方法'setParameter(java.lang.String, java.lang.Long, org.hibernate.type.LongType)'
  • 也适用于日期 -> ..setParameter("date", date, TemporalType.TIMESTAMP)
【解决方案2】:

如果您没有使用 Hibernate,但使用的是 EclipseLink,则可以使用查询提示: https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Query_Hints

示例 查询:

String insert = "INSERT INTO mytable VALUES ( ?, ?, ?, ?)";

em = getEntityManager();
em.getTransaction().begin();
Query u = em.createNativeQuery(insert);
u.setHint(QueryHints.BIND_PARAMETERS, HintValues.FALSE);//<--the hint
u.setParameter(1, "value1");
u.setParameter(2, "value2");
u.setParameter(4, "value4");//just skipped the null element
u.executeUpdate();
em.getTransaction().commit();

结果将是一个插入:

mytable
column1    column2    column3   column4
value1     value2               value4

当然如果“column3”在数据库中可以为空...

我不知道是否也适用于 Hibernate,但它可以。我使用 PostgreSQL 进行测试。

【讨论】:

    【解决方案3】:

    我在使用 EntityManager.createNamedQuery 时遇到了同样的问题(猜想 createNativeQuery 也有同样的问题)。

    如果您要将 nullable 参数传递给 Query,请使用允许传递类型的 TypedParameterValue。

    例如:

    setParameter("paramName", new TypedParameterValue(StandardBasicTypes.LONG, paramValue));
    

    在这里你显式设置传递值的类型,当你传递空值作为处理器时知道确切的类型。

    【讨论】:

    • 谢谢。这帮助了我的日期字段。 query.setParameter(6, new TypedParameterValue(StandardBasicTypes.CALENDAR_DATE, null));
    【解决方案4】:

    就我而言,使用 Oracle 12 和 jboss 7.3,我使用空字符串作为参数值解决了问题。我不明白为什么,但它有效。这是我的代码:

    String sql = "insert into customer (id,name,age) values (?1,?2,?3);
    em = getEntityManager();
    Query query = em.createNativeQuery(sql);
    query.setParameter(1, getId());
    query.setParameter(2, getName());
    if (getAge() != null) {//getAge() return BigDecimal and map a NUMBER column type
        query.setParameter(3, getAge());
    } else {
       query.setParameter(3, "");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-14
      • 1970-01-01
      • 2018-03-19
      • 1970-01-01
      • 2020-03-13
      • 2014-03-21
      • 1970-01-01
      相关资源
      最近更新 更多