Wie kann ich JPA / Hibernate so konfigurieren, dass Datum und Uhrzeit in der Datenbank als UTC-Zeitzone (GMT) gespeichert werden? Betrachten Sie diese kommentierte JPA-Entität:
public class Event {
@Id
public int id;
@Temporal(TemporalType.TIMESTAMP)
public java.util.Date date;
}
Wenn das Datum 2008-Feb-03 9:30 Uhr Pacific Standard Time (PST) ist, möchte ich, dass die UTC-Zeit von 2008-Feb-03 17:30 Uhr in der Datenbank gespeichert wird. Wenn das Datum aus der Datenbank abgerufen wird, möchte ich, dass es als UTC interpretiert wird. In diesem Fall ist 17:30 Uhr 17:30 Uhr UTC. Wenn es angezeigt wird, wird es als 9:30 Uhr PST formatiert.
Antworten:
Mit Hibernate 5.2 können Sie jetzt die UTC-Zeitzone mithilfe der folgenden Konfigurationseigenschaft erzwingen:
Weitere Informationen finden Sie in diesem Artikel .
quelle
useTimezone=true
der Verbindungszeichenfolge zu verwenden. Dannhibernate.jdbc.time_zone
funktioniert nur die EinstellungseigenschaftuseLegacyDatetimeCode
auf false setzenNach meinem besten Wissen müssen Sie Ihre gesamte Java-App in die UTC-Zeitzone stellen (damit Hibernate Daten in UTC speichert), und Sie müssen in die gewünschte Zeitzone konvertieren, wenn Sie Inhalte anzeigen (zumindest tun wir dies diesen Weg).
Beim Start machen wir:
Und stellen Sie die gewünschte Zeitzone auf das DateFormat ein:
quelle
Hibernate kennt keine Zeitzonen in Dates (weil es keine gibt), aber es ist tatsächlich die JDBC-Ebene, die Probleme verursacht.
ResultSet.getTimestamp
undPreparedStatement.setTimestamp
beide sagen in ihren Dokumenten, dass sie beim Lesen und Schreiben von / in die Datenbank standardmäßig Daten in / aus der aktuellen JVM-Zeitzone transformieren.Ich habe in Hibernate 3.5 eine Lösung für dieses Problem gefunden, indem ich eine Unterklasse erstellt habe
org.hibernate.type.TimestampType
, die diese JDBC-Methoden zwingt, UTC anstelle der lokalen Zeitzone zu verwenden:Dasselbe sollte getan werden, um TimeType und DateType zu reparieren, wenn Sie diese Typen verwenden. Der Nachteil ist, dass Sie manuell angeben müssen, dass diese Typen anstelle der Standardeinstellungen für jedes Datumsfeld in Ihren POJOs verwendet werden sollen (und auch die reine JPA-Kompatibilität beeinträchtigen), es sei denn, jemand kennt eine allgemeinere Überschreibungsmethode.
UPDATE: Hibernate 3.6 hat die Typ-API geändert. In 3.6 habe ich eine Klasse UtcTimestampTypeDescriptor geschrieben, um dies zu implementieren.
Wenn Sie beim Starten der App TimestampTypeDescriptor.INSTANCE auf eine Instanz von UtcTimestampTypeDescriptor setzen, werden alle Zeitstempel gespeichert und als in UTC behandelt, ohne dass die Anmerkungen zu POJOs geändert werden müssen. [Ich habe das noch nicht getestet]
quelle
UtcTimestampType
?UtcTimestampType
kompatibel?Date
oder einenTimestamp
JDBC-Treiber anwenden .Verwenden Sie bei Spring Boot JPA den folgenden Code in Ihrer Datei application.properties, und natürlich können Sie die Zeitzone nach Ihren Wünschen ändern
Dann in Ihrer Entity-Klassendatei
quelle
Hinzufügen einer Antwort, die vollständig auf einem Hinweis von Shaun Stone basiert und dem Divestoclimb verpflichtet ist. Ich wollte es nur im Detail formulieren, da es ein häufiges Problem ist und die Lösung etwas verwirrend ist.
Dies verwendet Hibernate 4.1.4.Final, obwohl ich vermute, dass alles nach 3.6 funktionieren wird.
Erstellen Sie zunächst den UtcTimestampTypeDescriptor von divestoclimb
Erstellen Sie dann UtcTimestampType, das UtcTimestampTypeDescriptor anstelle von TimestampTypeDescriptor als SqlTypeDescriptor im Super-Konstruktor-Aufruf verwendet, ansonsten aber alles an TimestampType delegiert:
Wenn Sie Ihre Hibernate-Konfiguration initialisieren, registrieren Sie UtcTimestampType als Typüberschreibung:
Jetzt sollten sich Zeitstempel nicht mehr mit der Zeitzone der JVM auf dem Weg zur und von der Datenbank befassen. HTH.
quelle
Sie würden denken, dass dieses häufige Problem von Hibernate behoben wird. Aber es ist nicht! Es gibt ein paar "Hacks", um es richtig zu machen.
Ich verwende das Datum als Long in der Datenbank. Ich arbeite also immer mit Millisekunden nach dem 1.1.70. Ich habe dann Getter und Setter in meiner Klasse, die nur Daten zurückgeben / akzeptieren. Die API bleibt also gleich. Der Nachteil ist, dass ich Longs in der Datenbank habe. Also mit SQL kann ich so ziemlich nur <,>, = Vergleiche machen - keine ausgefallenen Datumsoperatoren.
Ein anderer Ansatz besteht darin, einen benutzerdefinierten Zuordnungstyp wie hier beschrieben zu verwenden: http://www.hibernate.org/100.html
Ich denke, der richtige Weg, um damit umzugehen, ist die Verwendung eines Kalenders anstelle eines Datums. Mit dem Kalender können Sie die Zeitzone festlegen, bevor Sie fortfahren.
HINWEIS: Der alberne Stackoverflow lässt mich keinen Kommentar abgeben. Hier ist eine Antwort auf David A.
Wenn Sie dieses Objekt in Chicago erstellen:
Der Ruhezustand bleibt als "31.12.1969 18:00:00" erhalten. Die Daten sollten keine Zeitzone haben, daher bin ich mir nicht sicher, warum die Anpassung vorgenommen werden soll.
quelle
Calendar
Leseproblem zu lösen, sollte Hibernate oder JPA eine Möglichkeit bieten, für jede Zuordnung die Zeitzone anzugeben, in die Hibernate das Datum übersetzen soll, an dem es liest und in eineTIMESTAMP
Spalte schreibt .Timestamp
da wir dem JDBC-Treiber nicht unbedingt vertrauen können, dass Daten als gespeichert werden Wir würden erwarten.Hier sind mehrere Zeitzonen in Betrieb:
All dies kann unterschiedlich sein. Hibernate / JPA weist einen schwerwiegenden Designmangel auf, da ein Benutzer nicht einfach sicherstellen kann, dass Zeitzoneninformationen auf dem Datenbankserver gespeichert werden (was die Rekonstruktion korrekter Zeiten und Daten in der JVM ermöglicht).
Ohne die Möglichkeit, die Zeitzone mithilfe von JPA / Hibernate (einfach) zu speichern, gehen Informationen verloren, und sobald Informationen verloren gehen, wird die Erstellung teuer (wenn überhaupt möglich).
Ich würde argumentieren, dass es besser ist, immer Zeitzoneninformationen zu speichern (sollte die Standardeinstellung sein) und Benutzer dann die optionale Möglichkeit haben sollten, die Zeitzone zu optimieren (obwohl dies nur die Anzeige wirklich beeinflusst, gibt es in jedem Datum immer noch eine implizite Zeitzone).
Entschuldigung, dieser Beitrag bietet keine Problemumgehung (die an anderer Stelle beantwortet wurde), aber es ist eine Rationalisierung, warum es wichtig ist, immer Zeitzoneninformationen zu speichern. Leider scheinen viele Informatiker und Programmierer gegen die Notwendigkeit von Zeitzonen zu argumentieren, nur weil sie die Perspektive des "Informationsverlusts" nicht schätzen und wissen, dass dies Dinge wie die Internationalisierung sehr schwierig macht - was heutzutage bei Websites, auf die zugegriffen werden kann, sehr wichtig ist Kunden und Personen in Ihrer Organisation, die sich auf der ganzen Welt bewegen.
quelle
Bitte werfen Sie einen Blick auf mein Projekt auf Sourceforge, das Benutzertypen für Standard-SQL-Datums- und Uhrzeittypen sowie JSR 310 und Joda Time enthält. Alle Typen versuchen, das Ausgleichsproblem zu lösen. Siehe http://sourceforge.net/projects/usertype/
EDIT: Als Antwort auf die Frage von Derek Mahar, die diesem Kommentar beigefügt ist:
"Chris, arbeiten Ihre Benutzertypen mit Hibernate 3 oder höher? - Derek Mahar 7. November 10 um 12:30 Uhr."
Ja, diese Typen unterstützen Hibernate 3.x-Versionen, einschließlich Hibernate 3.6.
quelle
Das Datum liegt nicht in einer Zeitzone (es ist ein Millisekunden-Büro ab einem definierten Zeitpunkt, der für alle gleich ist), aber zugrunde liegende (R) DBs speichern Zeitstempel im Allgemeinen in politischem Format (Jahr, Monat, Tag, Stunde, Minute, Sekunde ,. ..) das ist zeitzonensensitiv.
Um es ernst zu nehmen, MUSS Hibernate innerhalb einer Form der Zuordnung mitgeteilt werden, dass sich das DB-Datum in der einen oder anderen Zeitzone befindet, damit es beim Laden oder Speichern keine eigene ...
quelle
Ich hatte genau das gleiche Problem, als ich die Daten in der Datenbank als UTC speichern und die Verwendung
varchar
und expliziteString <-> java.util.Date
Konvertierung vermeiden oder meine gesamte Java-App in der UTC-Zeitzone einstellen wollte (da dies zu weiteren unerwarteten Problemen führen könnte, wenn die JVM vorhanden ist in vielen Anwendungen geteilt).Es gibt also ein Open Source-Projekt
DbAssist
, mit dem Sie das Lesen / Schreiben als UTC-Datum aus der Datenbank einfach festlegen können. Da Sie JPA-Anmerkungen verwenden, um die Felder in der Entität zuzuordnen, müssen Sie lediglich die folgende Abhängigkeit in Ihre Maven-pom
Datei aufnehmen:Anschließend wenden Sie das Update an (Beispiel für den Ruhezustand + Spring Boot), indem Sie
@EnableAutoConfiguration
vor der Spring-Anwendungsklasse eine Anmerkung hinzufügen . Weitere Installationsanweisungen für Setups und weitere Anwendungsbeispiele finden Sie im Github des Projekts .Das Gute ist, dass Sie die Entitäten überhaupt nicht ändern müssen. Sie können ihre
java.util.Date
Felder so lassen, wie sie sind.5.2.2
muss der von Ihnen verwendeten Hibernate-Version entsprechen. Ich bin nicht sicher, welche Version Sie in Ihrem Projekt verwenden, aber die vollständige Liste der bereitgestellten Korrekturen finden Sie auf der Wiki-Seite des Githubs des Projekts . Der Grund, warum das Update für verschiedene Hibernate-Versionen unterschiedlich ist, liegt darin, dass Hibernate-Ersteller die API zwischen den Releases einige Male geändert haben.Intern verwendet das Update Hinweise von Divestoclimb, Shane und einigen anderen Quellen, um eine benutzerdefinierte Version zu erstellen
UtcDateType
. Anschließend wird der Standardjava.util.Date
dem Benutzer zugeordnet,UtcDateType
der alle erforderlichen Zeitzonen behandelt. Die Zuordnung der Typen erfolgt mithilfe von@Typedef
Anmerkungen in der bereitgestelltenpackage-info.java
Datei.Hier finden Sie einen Artikel , in dem erklärt wird, warum eine solche Zeitverschiebung überhaupt auftritt und wie diese gelöst werden kann.
quelle
Im Ruhezustand können keine Zeitzonen durch Anmerkungen oder auf andere Weise angegeben werden. Wenn Sie Kalender anstelle von Datum verwenden, können Sie eine Problemumgehung mithilfe der HIbernate-Eigenschaft AccessType implementieren und die Zuordnung selbst implementieren. Die fortgeschrittenere Lösung besteht darin, einen benutzerdefinierten Benutzertyp zu implementieren, um Ihr Datum oder Ihren Kalender zuzuordnen. Beide Lösungen werden in meinem Blogbeitrag hier erklärt: http://www.joobik.com/2010/11/mapping-dates-and-time-zones-with.html
quelle