LocalDateTime 和 SQL Server JDBC 4.2 驱动程序

Krz*_*tof 7 java sql-server jdbc mssql-jdbc

我正在尝试在java.time最新版本的 Sql Server JDBC 驱动程序中使用新类。正如我所读到的,它应该只适用于方法:PreparedStatement.setObject()ResultSet.getObject()

所以我创建了示例代码,但不能让它与 ResultSets 一起工作。我不知道我在这里做错了什么。

Connection connection = DriverManager.getConnection(connectionString);
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM myTable WHERE ? BETWEEN date_from AND date_to");
preparedStatement.setObject(1, LocalDateTime.now());   // That works

ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
    Object o = resultSet.getObject("date_from"); 
    o.getClass() returns java.sql.Timestamp

    LocalDateTime dateTime = resultSet.getObject("date_from", LocalDateTime.class);
}
Run Code Online (Sandbox Code Playgroud)

这会引发异常:

com.microsoft.sqlserver.jdbc.SQLServerException:不支持转换为类 java.time.LocalDateTime。

驱动版本:mssql-jdbc-6.5.4.jre8-preview.jar

SQL Server 版本:2016


https://docs.microsoft.com/en-us/sql/connect/jdbc/jdbc-4-2-compliance-for-the-jdbc-driver?view=sql-server-2017

如何解释底部表格中的这句话:

Java 8 中的新 Java 类:LocalDate/LocalTime/LocalDateTime、OffsetTime/OffsetDateTime

新的 JDBC 类型:TIME_WITH_TIMEZONE、TIMESTAMP_WITH_TIMEZONE、REF_CURSOR

REF_CURSOR is not supported in SQL Server. Driver throws a SQLFeatureNotSupportedException exception if this type is used. The driver supports all other new Java and JDBC type mappings as specified in the JDBC 4.2 specification.

Gor*_*son 9

我不知道我在这里做错了什么。

你没有做错任何事。您在7.1.0 版之前的 SQL Server 的 Microsoft JDBC 驱动程序中遇到了一个缺陷,这里讨论。

如果您使用的是 mssql-jdbc 7.1.0 或更高版本,则可以getObject(x, LocalDateTime.class)按预期使用。

对于 7.1.0 之前的 mssql-jdbc 版本,正如其他人所建议的,您需要检索 aTimestamp并将其转换为LocalDateTime. 但是,请注意,简单的解决方案......

LocalDateTime dateTime = resultSet.getTimestamp("date_from").toLocalDateTime()
Run Code Online (Sandbox Code Playgroud)

... 如果 JVM 的默认时区遵守夏令时,即“夏令时”,则会破坏某些日期/时间值。例如,

// time zone with Daylight Time
TimeZone.setDefault(TimeZone.getTimeZone("America/Edmonton"));

// test environment
Statement st = conn.createStatement();
st.execute("CREATE TABLE #tmp (id INT PRIMARY KEY, dt2 DATETIME2)");
st.execute("INSERT INTO #tmp (id, dt2) VALUES (1, '2018-03-11 02:00:00')");
ResultSet rs = st.executeQuery("SELECT dt2 FROM #tmp WHERE id=1");
rs.next();

// test code
LocalDateTime x = rs.getTimestamp("dt2").toLocalDateTime();  // bad

System.out.println(x.toString());
Run Code Online (Sandbox Code Playgroud)

将打印“2018-03-11T03:00”。请注意,时间是“03:00”,而不是“02:00”。

相反,您需要检索Timestampas UTC,然后将其转换LocalDateTime为 UTC,从而删除时区组件

// time zone with Daylight Time
TimeZone.setDefault(TimeZone.getTimeZone("America/Edmonton"));

// test environment
Statement st = conn.createStatement();
st.execute("CREATE TABLE #tmp (id INT PRIMARY KEY, dt2 DATETIME2)");
st.execute("INSERT INTO #tmp (id, dt2) VALUES (1, '2018-03-11 02:00:00')");
ResultSet rs = st.executeQuery("SELECT dt2 FROM #tmp WHERE id=1");
rs.next();

// test code
Timestamp ts = getTimestamp("dt2", Calendar.getInstance(TimeZone.getTimeZone("UTC")));
LocalDateTime x = LocalDateTime.ofInstant(ts.toInstant(), ZoneId.of("UTC"));  // good

System.out.println(x.toString());
Run Code Online (Sandbox Code Playgroud)

打印“2018-03-11T02:00”。