-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JDBC 4.2 for LocalTime, LocalDate & LocalDateTime #1478
Conversation
The follows other recent commits for OffsetDateTime & ZonedDateTime to defer to the driver’s JDBC 4.2 support for JSR 310 objects.
Thank you for the PR, @kdubb ! Could you explain the motive behind this change? |
MySQL and two PostgreSQL drivers support 4.2 types. Full disclosure, I'm the lead on pgjdbc-ng. Drivers, like ours, have made the switch completely and there is no translation to MyBatis already has specific handlers for Finally, you already made the decision not to support the drivers you mentioned by switching |
I noticed your contribution to pgjdbc-ng and pgjdbc when reviewing the earlier issue. :) I did some tests and verified that the current For the other two (i.e. Unlike [1] That's how
|
I am with @harawata on not changing the current implementation. Often jdbc drivers are just stored in some |
@kdubb Thank you for contributing! Would your proposed change work with the MariaDB Connector/J? I briefly looked at the source of the driver and it looks like even the most recent one does use the translations. |
@raupachz Thats a pretty glib way to view development in this day and age. I would say most development is done using tools with dependency management like Maven, Gradle, Ivy, etc. and they're including their driver in that. Also, clearly MariaDB Connector/J will support these changes; the fact that it internally uses conversion to other types is an implementation decision that should be left to the driver. Without these changes MyBatis is forcing the conversions and not leaving it to the driver. Finally, again, without these changes you have some proper support for JSR-310 types and not other, as a developer I find it extremely surprising that its done this way. If somebody is actually using and storing JSR-310 types, you would expect them to use a driver that supports them. It doesn't affect anybody not using JSR-310 types. Considering these were introduced in Java 8, this is more than likely not to affect legacy applications. |
@harawata PostgreSQL stores time & date values with microsecond precision & JSR-310 supports nanosecond precision. Forcing translation to |
Hi @kdubb , I might have been unclear. You modified three type handlers in this PR.
This statement is true only for The changes to the other two type handlers seem unnecessary to me because...
I have tested the 3.5.0 conversions with various DBs and couldn't find any problem. [1] Unlike
|
@harawata In my quick response to you I failed to mention on of the two reasons that this change should happen. Microsecond precision is one of them but the other is timezone conversion. The rules for JDBC This means calling While I used The only real way for
|
I actually ran the same tests with setting different default time zone from the server and they mostly worked [1]. [1] With MySQL 5.7.25 + Connector/J 8.0.15, the current implementation failed when selecting |
Hi @kdubb , We're planning to release 3.5.1 soon and I would like to include your change to the Thanks in advance! |
@harawata I've attached a simple test project (using pgjdbc-ng and Postgres) that displays the issue... I'll paste the test method here because it contains a good explanation. Note the test fails on mainline; using this branch the test will succeed. public void testLocalDateTime() {
// Force into Pacific Time timezone
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
// This following time is a valid "local date time" to be stored and retrieved, it should be unaltered when
// inserted and selected from the database as a "local date time"
//
// Note: the time itself does not exist in Pacific Time (our selected time zone), since it during the
// "time hole" created by setting clocks forward an hour at 2 am (thus becoming immediately 3 am) for
// Daylight Saving
//
// If mybatis forces conversion to java.sql.Timestamp (which requires a timezone) it will use the current default
// timezone. In this case it causes the value to change on its way into or out of the database.
//
// If mybatis uses LocalDateTime feature of JDBC 4.2 the value will not change on its way into or out of the
// database.
LocalDateTime value =
LocalDateTime.of(LocalDate.of(2019, MARCH, 10), LocalTime.of(2, 30));
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
mapper.insertLocalDateTime(value);
LocalDateTime found = mapper.selectLocalDateTime();
String foundRaw = mapper.selectRaw();
// Will currently fail (3:30 gets inserted due to "fixing" time in Pacific time zone
assertEquals(value, found);
assertEquals("2019-03-10 02:30:00", foundRaw);
} |
Thank you very much, @kdubb ! |
`java.sql.Date` and `java.sql.Timestamp` cannot hold a value that does not exist in the system's time zone and alter it implicitly. e.g. - In Pacific/Apia, `2011-12-30` becomes `2011-12-31` - In America/Los_Angeles, `2019-03-10 02:30` becomes `2019-03-10 03:30`
@kdubb, @harawata, I am one of the users using IBM DB2 and are therefore stuck with JDBC 4.0. What should we do? Thanks for your help. |
@mil7 The Java 8+ time library (aka |
Hi @mil7 , As a workaround, you can copy the old implementations to your project and register it globally in the config. Although they may work fine for most common usage, there are a few corner cases. |
We are using the Redshift JDBC 4.2 driver with mybatis 3.5.1. |
@sidamos We had issues with AWS Aurora MySQL, MariaDB JDBC 4.2 driver and MyBatis 3.5.1 that let us to not upgrade for a while. We had exceptions in said type handlers. In the end we found out that we stored some DateTime values in a VARCHAR column. Not sure if it is related, but maybe something to look into. |
The problem with the old type handlers is not something we can fix, unfortunately (I wouldn't have merged this PR otherwise). Simply put, @Test
void testTimestamp() throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
LocalDateTime ldt1 = LocalDateTime.of(2019, 3, 10, 2, 30);
LocalDateTime ldt2 = LocalDateTime.of(2019, 3, 10, 3, 30);
assertNotEquals(ldt1, ldt2); // PASS
Timestamp ts1 = Timestamp.valueOf(ldt1);
Timestamp ts2 = Timestamp.valueOf(ldt2);
assertNotEquals(ts1, ts2); // FAIL
} @sidamos , I just took a quick look at the classes in redshift-jdbc42 (1.2.27.1051) and it did not seem to support JSR-310 types. (Click to expand)@Test
void testForDemo() throws Exception {
Class.forName("xxx");
String url = "jdbc:xxx";
String username = "xxx";
String password = "xxx";
try (Connection con = DriverManager.getConnection(url, username, password)) {
try (Statement stmt1 = con.createStatement()) {
try {
stmt1.execute("drop table test");
} catch (Exception e) {}
stmt1.execute("create table test (id integer, t timestamp)");
}
LocalDateTime ldt = LocalDateTime.now();
int id = 1;
try (PreparedStatement stmt = con.prepareStatement("insert into test (id, t) values (?, ?)")) {
stmt.setInt(1, id);
stmt.setObject(2, ldt);
stmt.execute();
}
try (PreparedStatement stmt = con.prepareStatement("select t from test where id = ?")) {
stmt.setInt(1, id);
try (ResultSet rs = stmt.executeQuery()) {
rs.next();
assertEquals(ldt, rs.getObject(1, LocalDateTime.class));
}
}
}
} If it works on some machines, check if there is an older version of MyBatis JAR in the classpath. |
Although I am sensitive the issues people are experiencing, the issue is not with these handlers. The issue is with specific drivers JDBC 4.2 conformance. JDBC < 4.2 supports Date/Time types using the requisite values in MyBatis cannot be expected to fix non-conforming or unsupported drivers in this case because, as @harawata and myself have pointed out, there are issues with the values themselves. |
Apologies I meant to direct that at @sidamos. |
For the record, I myself think it's OK to use JSR-310 classes with JDBC <4.2 drivers because I believe they added Anyway, if the driver you are using does not work with the new type handlers, you should contact the developer and ask them to release a new driver (if the driver is open-source, I would be happy to take a look. :) ) |
The strange thing with the Redshift driver is that LocalDate works OK on some machines and not on others. |
@harawata So, I guess, the newer JDBC 4.2 driver from Redshift still does not support JSR-310. |
@sidamos , |
Update LocalDateTypeHandler, LocalTimeTypeHandler and LocalDateTimeTypeHandler to use `PreparedStatement#setObject()` and `ResultSet#getObject()`. This fixes the following potential issues. - LocalTimeTypeHandler : fractional seconds (nanoseconds) part is lost. - LocalDateTimeTypeHandler, LocalDateTypeHandler : value could be altered.
The follows other recent commits for OffsetDateTime & ZonedDateTime to defer to the driver’s JDBC 4.2 support for JSR 310 objects.