用Types.TIME将java.time.LocalTime持久化到oracle中,会失去小数点的秒数精度。

问题描述 投票:2回答:1

我有一个与Oracle的行为,我不知道是有意还是无意。

我在玩java datetime API的各种类型,在JDBC级别使用它们。

我试图将java.time.LocalTime的一个实例持久化到oracle数据库中。

在JDBC级别,我的理解是,我应该使用.NET Framework 2.0和.NET Framework 3.0。

  • 一个兼容JDBC 4.2的驱动程序
  • PreparedStatement.setObject(int parameterIndex, Object x, int targetSqlType)
  • 将Types.TIME作为java.time.LocalTime实例的目标SqlType。

由于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。

所以我想我的问题有两个方面。

  • 我假设LocalTime的标准JDBC映射是:ps.setObject(1, localTime, Types.TIME),是否正确?如果不是,那么所谓的JDBC方式是什么?
  • 是否打算采用Oracle的行为?如果是,它是否在某个地方被记录下来?

另外,这是我的第一个SO问题,所以欢迎任何反馈。

祝你编码愉快

oracle jdbc java-time localtime jsr310
1个回答
0
投票

Oracle数据库以Oracle SQL DATE格式存储时间值。Oracle SQL DATE不存储小数秒。如果小数秒很重要,那么使用JDBCType.TIMESTAMP。

SQL规范很微妙(轻描淡写)。所有厂商对SQL的实现都略有不同。SQL规范足够灵活,所有主要的SQL数据库都符合要求,非常包括Oracle数据库。厂商的数据库之间存在很大的差异,随意阅读SQL规范可能会产生误导。Oracle数据库将TIME表示为DATE是允许的,不存储小数秒也是允许的。

编辑补充。https:/docs.oracle.comendatabaseoracle-database19sqlrfData-Typees.html#GUID-7B72E154-677A-4342-A1EA-C74C1EA928E6。

© www.soinside.com 2019 - 2024. All rights reserved.