我有一个与Oracle的行为,我不知道是有意还是无意。
我在玩java datetime API的各种类型,在JDBC级别使用它们。
我试图将java.time.LocalTime的一个实例持久化到oracle数据库中。
在JDBC级别,我的理解是,我应该使用.NET Framework 2.0和.NET Framework 3.0。
由于oracle没有提供TIME类型,我使用了TIMESTAMP字段。
问题是,如果我在JDBC级别使用Types.TIME,我就会失去小数点秒的精度。
如果我使用Types.TIMESTAMP,精度就会保持不变。
如果可能的话,我想使用JDBC为LocalTime设计的标准映射。
这里的测试显示了这种行为。
@Test
public void testSetObjectWithSqlTypeTimestamp() {
testSetObjectWithSqlType("java.sql.Types.TIMESTAMP", Types.TIMESTAMP);
}
@Test
public void testSetObjectWithSqlTypeTime() {
testSetObjectWithSqlType("java.sql.Types.TIME", Types.TIME);
}
private void testSetObjectWithSqlType(String sqlTypeLabel, Integer sqlTypeValue) {
logger.info("Testing setObject with {} (value={})", sqlTypeLabel, sqlTypeValue);
LocalTime willBeInserted = LocalTime.of(21, 17, 23, 678_987_000);
Connection con = null;
PreparedStatement ps = null;
try {
con = dataSource.getConnection();
con.setAutoCommit(false);
ps = con.prepareStatement("insert into LOCAL_TIME_TABLE (FOO) values (?)");
ps.setObject(1, willBeInserted, sqlTypeValue);
ps.executeUpdate();
con.commit();
} catch (SQLException e) {
rollbackQuietly(con);
throw new RuntimeException("Error inserting test value", e);
} finally {
JdbcUtils.closeStatement(ps);
JdbcUtils.closeConnection(con);
}
List<LocalTime> results = jdbcTemplate.queryForList("select FOO from LOCAL_TIME_TABLE", LocalTime.class);
assertThat(results)
.containsExactlyInAnyOrder(willBeInserted)
.hasSize(1);
}
Types.TIMESTAMP测试工作正常。
Types.TIME测试有以下错误。
[ERROR] Failures:
[ERROR] LocalTimeSetObjectWithSqlTypeOracleBugTest.testSetObjectWithSqlTypeTime:44->testSetObjectWithSqlType:72
Expecting:
<[21:17:23]>
to contain exactly in any order:
<[21:17:23.678987]>
elements not found:
<[21:17:23.678987]>
and elements not expected:
<[21:17:23]>
这是一个spring-boot测试(DataSource和JdbcTemplate是由spring提供的).我没有详细说明所有的spring boilerplate代码,这似乎与问题无关;但如果需要的话,我会添加它。
我的FOO表是这样的。
create table LOCAL_TIME_TABLE (
FOO timestamp
);
我使用的是下面的Oracle镜像。https:/hub.docker.comrwnamelessoracle-xe-11g-r2。
而下面的驱动(maven坐标):com.oracle.database.jdbc:ojdbc10:19.3.0.0。
所以我想我的问题有两个方面。
另外,这是我的第一个SO问题,所以欢迎任何反馈。
祝你编码愉快
Oracle数据库以Oracle SQL DATE格式存储时间值。Oracle SQL DATE不存储小数秒。如果小数秒很重要,那么使用JDBCType.TIMESTAMP。
SQL规范很微妙(轻描淡写)。所有厂商对SQL的实现都略有不同。SQL规范足够灵活,所有主要的SQL数据库都符合要求,非常包括Oracle数据库。厂商的数据库之间存在很大的差异,随意阅读SQL规范可能会产生误导。Oracle数据库将TIME表示为DATE是允许的,不存储小数秒也是允许的。