JPA 在使用日期条件和 SQL datetime2 时截断纳秒
JPA truncates nanoseconds when using date criteria & SQL datetime2
我正在尝试创建一个涉及 SQL Server datetime2 字段(精确到 100 纳秒)的 where 子句;使用 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
类型,只支持毫秒。
这更像是一种解决方法;这是我为解决问题所做的工作:
如问题更新中所述,不支持 datetime2 参数的是 jtds 驱动程序。我只是转向了 Microsoft 驱动程序 - 问题已解决。
一些进一步的解决方法:
- 嵌入一个 Convert() 函数调用,包装参数文字;发送时间戳字符串值。
- 修复 jtds 代码 - 显然 jdbc 支持 nanos
我正在尝试创建一个涉及 SQL Server datetime2 字段(精确到 100 纳秒)的 where 子句;使用 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
类型,只支持毫秒。
这更像是一种解决方法;这是我为解决问题所做的工作:
如问题更新中所述,不支持 datetime2 参数的是 jtds 驱动程序。我只是转向了 Microsoft 驱动程序 - 问题已解决。
一些进一步的解决方法:
- 嵌入一个 Convert() 函数调用,包装参数文字;发送时间戳字符串值。
- 修复 jtds 代码 - 显然 jdbc 支持 nanos