【问题标题】:JPA truncates nanoseconds when using date criteria & SQL datetime2JPA 在使用日期标准和 SQL datetime2 时截断纳秒
【发布时间】:2015-06-04 12:24:43
【问题描述】:

我正在尝试创建一个涉及 SQL Server datetime2 字段的 where 子句(精确到 100 纳秒);使用 JPA 和 Hibernate。

我的代码如下所示:

CriteriaBuilder cb = em.getCriteriaBuilder();
List<Predicate> predicates = new ArrayList<>();
CriteriaQuery(X) q = cb.createQuery(X.class);
Root<X> root = q.from(X.class);

java.sql.Timestamp mySqlTimeStamp = Timestamp.valueOf("2015-06-04 11:31:53.2119339");

predicates.add(cb.greaterThan(root.get("DateModified"), mySqlTimeStamp))

q.where(predicates.toArray(new Predicate[predicates.size()]));

em.createQuery(q).getResultList();

SQL Server Profiler 显示时间戳参数值被截断为2015-06-04 11:31:53.210 - 很奇怪,这甚至不是四舍五入。不用说,我的结果集不准确。

如果我手动将参数更改为完整值 2015-06-04 11:31:53.2119339 一切都很好。

问题是,如何让 JPA 截断日期?

另外,如何为我的时间戳字段注入我自己的参数值序列化器?

帮助表示赞赏;谢谢

更新 我已经将它跟踪到这个 jtds jdbc 代码: net.sourceforge.jtds.jdbc.JtdsPerparedStatement:

protected void setParameter(int parameterIndex, Object x, int targetSqlType, int scale, int length)
        throws SQLException {
        ParamInfo pi = getParameter(parameterIndex);

        if ("ERROR".equals(Support.getJdbcTypeName(targetSqlType))) {
            throw new SQLException(Messages.get("error.generic.badtype",
                                Integer.toString(targetSqlType)), "HY092");
        }

        // Update parameter descriptor
        if (targetSqlType == java.sql.Types.DECIMAL
            || targetSqlType == java.sql.Types.NUMERIC) {

            pi.precision = connection.getMaxPrecision();
            if (x instanceof BigDecimal) {
                x = Support.normalizeBigDecimal((BigDecimal) x, pi.precision);
                pi.scale = ((BigDecimal) x).scale();
            } else {
                pi.scale = (scale < 0) ? TdsData.DEFAULT_SCALE : scale;
            }
        } else {
            pi.scale = (scale < 0) ? 0 : scale;
        }

        if (x instanceof String) {
            pi.length = ((String) x).length();
        } else if (x instanceof byte[]) {
            pi.length = ((byte[]) x).length;
        } else {
            pi.length   = length;
        }

        if (x instanceof Date) {
            x = new DateTime((Date) x);
        } else if (x instanceof Time) {
            x = new DateTime((Time) x);
        } else if (x instanceof Timestamp) {
            x = new DateTime((Timestamp) x);
        }

        pi.value = x;
        pi.jdbcType = targetSqlType;
        pi.isSet = true;
        pi.isUnicode = connection.getUseUnicode();
    }
}

这里的时间戳强制为net.sourceforge.jtds.jdbc.DateTime类型,只支持毫秒。

【问题讨论】:

  • 我猜你的意思是“Timestamp.valueOf(...)”而不是新的。我使用 H2 数据库和 DataNucleus JPA 做了类似的事情,我的 nanos 被传递到数据存储区。也许看看 Hibernate 在日志中放入了什么以及 SQLServer JDBC 驱动程序在做什么?
  • 是的,valueOf() - 我已经更正了代码。我还没有通过 nanos 更新等 - 但正在使用 JPA 成功阅读它们。您是否使用标准中的参数取得了成功?
  • 你的意思是,在上面的 Criteria 中,只需放置一个 cb.parameter 然后在查询上调用 setParameter (而不是使用文字)?是的,这对我有用 H2+DataNucleus

标签: java sql-server hibernate jpa datetime2


【解决方案1】:

这更像是一种解决方法;这是我为解决问题所做的:

如问题更新中所述,不支持 datetime2 参数的是 jtds 驱动程序。我只是转移到 Microsoft 驱动程序 - 问题解决了。

一些进一步的解决方法:

  • 嵌入 Convert() 函数调用,包装参数文字;发送时间戳字符串值。
  • 修复 jtds 代码 - 显然 jdbc 支持 nanos

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 1970-01-01
    • 2010-10-29
    相关资源
    最近更新 更多