MySQL DateTime(3)

Hallo Community,

ich habe eine Spalte in MySQL mit DateTime(3) deklariert, aber die Millisekunden sind nach einem Insert von
new java.sql.Date()
immer 000 (Bsp.: 2015-08-29 02:29:30.000)

Ich hätte erwartet, da Date() mindestens Millisekunden verarbeiten kann, dass dies problemlos funktioniert.

Ich nutze MyBatis und füge die Daten mittels den Modelklassen vom Generator ein:

v.setDate(new Date());
v.setEnabled(true);
m.insertSelective(v);

Mache ich was falsch, liegt es an MyBatis, oder muss ich sogar das Problem in JDBC suchen?

Welche Version von MySQL verwendest du denn?
Das sollte erst ab Version >= 5.6.4 funktionieren, selbst dann gibt es Bugs (https://bugs.mysql.com/bug.php?id=64686).

Ansonsten sind Temporaere DB Typen nicht portabel und machen gern Aerger, ist ein recht komplexes Thema, wir nehmen nur noch long zum speichern und UTC Zeit zur interpretation (Joda Time), kommt aber sehr auf deinen Anwendungsfall an.

es gibt jedenfalls bei JDBC Date vs Timestamp
java.util.Date vs java.sql.Date - Stack Overflow
Date Richtung DB durchaus verdächtig, Millisekunden zu vernachlässigen,
beim Lesen evtl. noch mehr als beim Schreiben, wie prüfst du den Wert in der DB?
dort gelesen mit welchem Tool oder erst wieder in Java erneut als Date?

ob und wie bei MyBatis, was immer das ist, zu beeinflussen, ist die nächste Frage,
Hibernate-Mapping kann das wohl unterscheiden:
Hibernate Mapping Types

soviel an Stichpunkten ohne genaue Kenntnis zu allem…

danke
Ich habe mysql5.7
Prüfen tue ich das Ganze über mysql workbench. Sobald der Datentyp Datetime(3) ist werden die Millisekunden auch angezeigt.
@maki : long statt datetime? Ist da die Fehlersuche nicht etwas schwieriger, da der Zeitstempel erst gewandelt werden muss? Gibt es Probleme mit den Zeitzonen? Ich brauche es hauptsächlich für Create-, Update- und Invalidate Zeitstempel, die natürlich auch so in der GUI verwendet werden.
@SlaterB : danke. Werde mich mal in deine Links rein lesen.

*** Edit ***

Ich habe mal das Traceing auf den MyBatis Mapper angeschmissen:


2015-11-26 21:14:31,872 DEBUG: 142   ==>  Preparing: INSERT INTO cvalues (value, Config_id, enabled, created, updated) VALUES (?, ?, ?, ?, ?) 
2015-11-26 21:14:31,895 DEBUG: 142   ==> Parameters: 496.84418970538394(Double), 2(Long), true(Boolean), 2014-11-26 21:14:31.576(Timestamp), 2015-11-26 21:14:31.576(Timestamp)

Offensichtlich ist die Info auf höhe PreparedStatement noch vorhanden. Und wenn ich auf die DB folgendes absetze:
[SQL]INSERT INTO cvalues (value, Config_id, enabled, created, updated) VALUES (496.84418970538394, 2, true, ‘2014-11-26 21:14:31.576’, ‘2015-11-26 21:14:31.576’) ;[/SQL]

Dann ist die Info tatsächlich vorhanden. Die Logausgaben sind zwar von Mybatis, aber ich vermute mal, dass dies Logs sind,wie die Java API aufgerufen wird.

*** Edit ***

OK, um es noch einen Schritt weiter einzugrenzen folgender Test:

		SqlSession sess = con.getNewSession();
	
		Connection conn = sess.getConnection();
		PreparedStatement ps = conn.prepareStatement("INSERT INTO cvalues (value, Config_id, enabled, created, updated) VALUES (?, ?, ?, ?, ?)");
		ps.setDouble(1, 496.84418970538394);
		ps.setLong(2, 2);
		ps.setBoolean(3, true);
		ps.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
		ps.setTimestamp(5, new Timestamp(System.currentTimeMillis()));
		ps .executeUpdate();
		conn.commit();

Auch hier erscheinen bereits die “000” beim auslesen.

*** Edit ***

Problem ist gelöst. Ich habe mysql connector von 5.1.21 auf 5.1.37 geupdated … damit geht es nun.

Ich habe den versuch gestartet, nachdem ich im Bugtracker von MySQL von dem Problem gelesen habe: https://bugs.mysql.com/bug.php?id=60584

Danke für die Unterstützung.

long + UTC = keine Fehlersuche IME :slight_smile:

Die JVM nimmt einfach die Zeitzone des OS wenn keine explizit angegeben wurde… das setzt also voraus das alles ueberall richtig gemacht wurde.
Dazu kommt, das TIMESTAMP, DATETIME, etc. pp. sehr unterschiedlich sind in verschiedenen RDBMS.
Fuer die GUI wandelt man dann einfach seinen UTC long in das gewuenschte Format.

Sowas ist wichtig wenn man SW fuer Server schreibt, die irgendwo auf der Welt stehen koennten., oder wenn man viele RDBMS unterstuetzen muss.

So ein Bug im JDBC Treiber ist dann auch egal weil nicht relevant fuer long :slight_smile:

Ich meinte eher Support … wenn man in der DB mal was nachvollziehen muss, sieht man in der Regel nur lange Zahlen, die erst in ein für Menschen lesbares Format gewandelt werden muss. Klar kann man alles machen. Sortieren ist gar kein Problem, aber schon die Abfrage „Zeige mir die Daten zwischen heute 9Uhr und 10Uhr“ wird kompliziert, weil man die zum einen wandeln muss (und dann noch mit Zeitzoneninfo???). Oder einfach nur das Lesen ist schwieriger.
Ein [SQL]SELECT * FROM[/SQL] kann man ja dann grundsätzlich vergessen, wenn ich den Zeitstempel lesen möchte. Wie sieht da die Praxis aus? Kann es mir grad nicht vorstellen.

Ansonsten sollten doch 2 Rechner, die in unterschiedlichen Zeitzonen stehen da auch keine Probleme verursachen. Die verhalten sich genauso, als wenn ich Date() verwenden würde, oder?

Ich bin aber grundsätzlich angetan von der Idee.

was heißt ‚auch‘, mit long liegt die Kontrolle allein beim jeweiligen Client/ Rechner, entweder achtet der auf korrekte Werte oder nicht, DB hat nichts zu tun,

bei Verwendung von DATETIME & Co. könnte man schon eher manchen Unfug vermuten:

MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME.) By default, the current time zone for each connection is the server’s time. The time zone can be set on a per-connection basis.

https://dev.mysql.com/doc/refman/5.5/en/datetime.html

wenn die beiden Client nicht auf eigene Zeitzone in der Connection achten,
oder gar DATETIME senden wo anscheinend Zeitzone keine Rolle spielt (?!),
wenn dann jeder Client sein 9:00 schickt, welche real x Stunden auseinander liegen, dann werden sie im Server vielleicht zur gleichen Zeit gespeichert?..

[QUOTE=freezly]Ich meinte eher Support … wenn man in der DB mal was nachvollziehen muss, sieht man in der Regel nur lange Zahlen, die erst in ein für Menschen lesbares Format gewandelt werden muss. Klar kann man alles machen. Sortieren ist gar kein Problem, aber schon die Abfrage “Zeige mir die Daten zwischen heute 9Uhr und 10Uhr” wird kompliziert, weil man die zum einen wandeln muss (und dann noch mit Zeitzoneninfo???). Oder einfach nur das Lesen ist schwieriger.
Ein [SQL]SELECT * FROM[/SQL] kann man ja dann grundsätzlich vergessen, wenn ich den Zeitstempel lesen möchte. Wie sieht da die Praxis aus? Kann es mir grad nicht vorstellen.[/QUOTE]

Wenn man in die DB gucken möchte und dort ein lesbares Datum benötigt, kann man sich einen View mit gewünschtem Datumsformat erstellen. Auf dieser ‘virtuellen Tabelle’ kann man dann ganz normal Abfragen laufen lassen.

Ich weiß allerdings nicht genau, ob alle RDBMS diese Funktion unterstützen. MySQL hat diese Funktion zumindest in der Version 5.7: MySQL 5.7 Referende Manual - Create View Syntax

Das ist natuerlich richtig, fuer DBAs die direkt auf der DB per SQL rumhacken ist long umstaendlich.

[quote=SlaterB;126267]wenn die beiden Client nicht auf eigene Zeitzone in der Connection achten,
oder gar DATETIME senden wo anscheinend Zeitzone keine Rolle spielt (?!),
wenn dann jeder Client sein 9:00 schickt, welche real x Stunden auseinander liegen, dann werden sie im Server vielleicht zur gleichen Zeit gespeichert?..[/quote]
Oder schlimmer noch: Ein Server hat die falsche Zeitzone und die JVM wurde ohne explizite gestartet… passiert oefters als man glaubt.

Das wuerde funzen, „richtige“ RDBMS haben das, ist schon lange Teil des SQL standards, aber extra eine View anlegen gefaellt bestimmt nicht jedem…
Anderseits haben viele RDBMS SQL funktionen die long hin und her konvertieren (FROM_UNIXTIME usw. usf.), ist aber trotzdem aufwaendiger, aber man kann nicht immer alles haben :slight_smile: