Wir haben eine Spring + Hibernate Java 7 Web-Anwendung. Derzeit verwenden wir .hbm.xml
Hibernate-Dateien (anstelle der allgemeineren bekannten Annotationen) als Zuordnung zwischen den Java-Entitäten und den Datenbanktabellen.Oracle getTime() keep Millisekunden
Einer unserer Java Entitätsklassen hat eine java.util.Date
millisekundengenau:
public class SomeEntity extends AbstractEntity{
...
private java.util.Date someDate; // with ms precision
...
}
In unserer .hbm.xml
Datei haben wir die zu diesem Zeitpunkt:
...
<hibernate-mapping>
<class name="com.namespace.Entity" table="entity" batch-size="10">
...
<property name="SomeDate" column="somedate" type="com.namespace.CustomDateType" />
...
, die zu einer Datenbanktabelle verknüpft ist mit folgender Zeile:
SOMEDATE TIMESTAMP(2) NULLABLE=Yes
O ur CustomDateType
Klasse:
package com.namespace.type;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Date;
import org.hibernate.usertype.UserType;
public class CustomDateType implements UserType {
private static final int[] SQL_TYPES = { Types.TIMESTAMP };
@Override
public Object assemble(final Serializable serializable, final Object o) {
return deepCopy(serializable);
}
@Override
public Object deepCopy(final Object value) {
return value;
}
@Override
public Serializable disassemble(final Object o) {
return (Serializable) deepCopy(o);
}
@Override
public boolean equals(final Object x, final Object y) {
if (x == y) {
return true;
} else if ((x == null) || (y == null)) {
return false;
}
return x.equals(y);
}
@Override
public int hashCode(final Object o) {
return ((CustomDateType) o).hashCode();
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Object nullSafeGet(final ResultSet resultSet, final String[] names, final Object owner) throws SQLException {
Date result = null;
final Timestamp timestamp = resultSet.getTimestamp(names[0]); // This is where the problem is
if (!resultSet.wasNull()) {
result = new Date(timestamp.getTime());
}
return result;
}
@Override
public void nullSafeSet(final PreparedStatement statement, final Object value, final int index) throws SQLException {
final Date dateToSet = (Date) value;
statement.setTimestamp(index, dateToSet == null ? null : new Timestamp(dateToSet.getTime()));
}
@Override
public Object replace(final Object o, final Object o1, final Object o2) {
return o;
}
@Override
public Class<Date> returnedClass() {
return Date.class;
}
@Override
public int[] sqlTypes() {
return SQL_TYPES;
}
}
Wenn someDate
Debuggen tatsächlich Millisekunden in der Java-Klasse hat. Aber in der CustomDateType#nullSafeGet
Methode hat das resultierende TimeStamp
keine Millisekunden mehr.
Der resultSet
Parameter ist die oracle.jdbc.driver.ForwardOnlyResultSet
, die in oracle.jdbc.driver.T4CPreparedStatement
weiter, die die Klasse & Verfahren weiterhin in denen der Kern des Problems ist: oracle.jdbc.driver.DateTimeCommonAccessor#getTime(int, Calendar)
In diesem Verfahren wird die milliseconds
abgezogen werden und Sie sind mit second
links - Präzision.
Gibt es eine Möglichkeit, die Millisekunden in dieser Situation zu halten? Wie kann man Millisekunden-Genauigkeit sparen, wenn man von java.util.Date
zur Datenbank TIMESTAMP
-type column geht?
HINWEIS: Die Millisekunden sind bereits verschwunden, bevor Sie in die Datenbanktabelle gehen. Wenn ich einen Breakpoint bei final Timestamp timestamp = resultSet.getTimestamp(names[0]);
setze und übergehe, hat das resultierende timestamp
keine Millisekunden mehr.
EDIT: Der Inhalt des hava.util.Date
Objekt und java.sql.Timestamp
Objekte während der Fehlersuche:
Die fraction
und millis
beide entnommen und auf 0
..
sollten Sie 'java.sql.Timestamp' für Timestamp-Spalten verwenden. Nicht 'java.util.Date' –
Warum erhalten Sie zuerst einen' java.sqlTimestamp' und dann einen 'java.sql.Time'. Beachten Sie, dass 'java.sql.Time' eine Genauigkeit in Sekunden, nicht in Millisekunden hat (beachten Sie, dass die Dokumentation nicht vollständig klar ist, müssen Sie zwischen den Zeilen für diese Einschränkung lesen) java.sql.Timestamp'. –
@MarkRotteveel Hmm ok, ich verstehe zwar, dass 'Time' und' Timestamp' unterschiedliche Genauigkeit haben, und dieser Oracle JDBC 'getTime' Aufruf ist die Wurzel des Problems. Aber wenn ich streng auf unseren eigenen Code schaue, sehe ich 'Timestamp timestamp = resultSet.getTimeStamp (names [0]);'. Danach werden die Dinge von 'oracle.jdbc' aufgerufen, und aus irgendeinem Grund endet es bei' DateTimeCommonAccessor # getTime (...) 'anstelle von' getTimestamp (...) '. Ich werde untersuchen, wo es vom ursprünglichen getTimestamp in getTime übergeht, aber haben Sie vielleicht eine Idee, wo dies passieren könnte, und noch wichtiger: warum/wie? –