繁体   English   中英

如何将SQL DATE映射到LocalDate

[英]How to map sql DATE to LocalDate

我想将LocalDate存储在DATE列中并保持不变。 根据定义, DATELocalDate均为“本地”类型。 因此, 时区的概念不应以任何方式干涉。

下面的代码是一个最小示例,该示例在内存数据库中创建一个带有DATE列的表。 Maven工件com.h2database:h2:1.4.192必须在类路径中。

首先,定义insertretrieve方法:

static void insert(DataSource ds, String date) throws SQLException {
  try (Connection conn = ds.getConnection();
       Statement stmt = conn.createStatement()) {
    stmt.execute("CREATE TABLE people (id BIGINT NOT NULL AUTO_INCREMENT"
      + ", born DATE NOT NULL, PRIMARY KEY (id) );");
    stmt.execute("INSERT INTO people (born) VALUES ('" + date + "')");
  }
}

static LocalDate retrieve(DataSource ds) throws SQLException {
  try (Connection conn = ds.getConnection();
       Statement stmt = conn.createStatement();
       ResultSet rs = stmt.executeQuery("SELECT * FROM people limit 1")) {
    if (rs.next()) {
      java.sql.Date retrieved = java.sql.Date.valueOf(rs.getString("born"));
      return retrieved.toLocalDate();
    }
    throw new IllegalStateException("No data");
  }
}

注意, insert方法在单引号中使用LocalDatetoString值,因此Java™没有机会创建时区歧义。 现在打电话insert一次,然后多次retrieve ,每次用不同的timzone设置:

public static void main(String[] args) throws Exception {
  DataSource ds = JdbcConnectionPool.create("jdbc:h2:mem:test", "sa", "sa");
  LocalDate born = LocalDate.parse("2015-05-20");
  insert(ds, born.toString());
  System.out.println("Inserted:  " + born);
  for (int i : new int[]{-14, 0, 12}) {
    TimeZone z = TimeZone.getTimeZone(String.format("Etc/GMT%+02d", i));
    TimeZone.setDefault(z);
    System.out.println("Retrieved: " + retrieve(ds));
  }
}

然后打印以下内容:

Inserted:  2015-05-20
Retrieved: 2015-05-20
Retrieved: 2015-05-19
Retrieved: 2015-05-18

假设数据库表不变,如何编写retrieve方法,使其返回无条件插入的相同值?

我只是尝试对您的retrieve方法进行以下修改,但对我有用:

DATE类型H2文档说它是

日期数据类型。 格式为yyyy-MM-dd。

所以,而不是你的...

java.sql.Date retrieved = (java.sql.Date) rs.getObject("born");
return retrieved.toLocalDate();

我刚用过

return LocalDate.parse(rs.getString("born"));

...和我的代码产生

Inserted:  2015-05-20
Retrieved: 2015-05-20
Retrieved: 2015-05-20
Retrieved: 2015-05-20

以下解决方案也适用。 我更喜欢在接受的答案中通过String进行转换,因为它避免了如下所示的时区调整。 但是,它可能无法在所有数据库上以相同的方式工作,因为某些数据库(例如Oracle)具有不同的DATE定义。

static LocalDate retrieve(DataSource ds) throws SQLException {
  try (Connection conn = ds.getConnection();
       Statement stmt = conn.createStatement();
       ResultSet rs = stmt.executeQuery("SELECT * FROM people limit 1")) {
    if (rs.next()) {
      ZoneId utc = ZoneId.of("UTC");
      TimeZone z = TimeZone.getTimeZone(utc);
      Calendar cal = Calendar.getInstance(z);
      java.sql.Date retrieved = rs.getDate("born", cal);
      long time = retrieved.getTime();
      java.util.Date utilDate = new java.util.Date(time);
      Instant instant = utilDate.toInstant();
      ZonedDateTime zdt = instant.atZone(utc);
      return zdt.toLocalDate();
    }
  }
  throw new IllegalStateException("No data");
}

正如用户Tunaki所建议的那样,此问题概述了通过java.util.Date的转换:是否缺少在Java 8中修复JDBC日期处理的机会?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM