ResultSet.getDate() 一定丢秒数,因 java.sql.Date 构造时强制将时分秒毫秒置零;应改用 getTimestamp() 读取完整时间,并配合 setTimestamp() 或 setObject(..., JDBCType.TIMESTAMP) 写入。
ResultSet.getDate() 会丢秒数,不是 Java 11 的问题,是 java.sql.Date 类本身的设计行为。
为什么 getDate() 一定丢时间部分
java.sql.date 是 java.util.date 的子类,但它重写了构造逻辑和 tostring():只要实例化,就强制把时、分、秒、毫秒全部设为 0。jdbc 驱动看到 oracle 的 date 列,默认按规范映射成 java.sql.date,不加判断也不做保留。
- 哪怕数据库里存的是
2026-06-24 14:35:47,rs.getDate("col")返回的也是2026-06-24 00:00:00 -
ResultSet.getObject("col")底层默认走的就是getDate()路径,结果一样 -
SimpleDateFormat格式化它也永远输出00:00:00——值本身就没有,不是显示问题
getTimestamp() 才能读出完整时间
ResultSet.getTimestamp("col") 不看字段声明类型,直接从网络包里提取原始字节。Oracle DATE 存了年月日+时分秒(精度到秒),getTimestamp() 全认,返回 java.sql.Timestamp,秒数保留,毫秒补 0。
- 无需改数据库字段类型,
DATE列直接调getTimestamp()即可 - 搭配
LocalDateTime更干净:rs.getTimestamp("col").toLocalDateTime() - MyBatis 必须在
<resultmap></resultmap>里显式写jdbcType="TIMESTAMP",否则可能又 fallback 到DATE映射
写入时用 setTimestamp(),别用 setDate()
光读对了不行,写入也得一致。用 PreparedStatement.setDate(1, date) 往 DATE 列写,时间照样被清零。
- 改用
ps.setTimestamp(1, Timestamp.valueOf(localDateTime)) - 更稳妥:用
ps.setObject(1, localDateTime, JDBCType.TIMESTAMP),强制走 TIMESTAMP 协议路径 - 旧版驱动(如 ojdbc6)可能需连接 URL 加
?oracle.jdbc.javaTimeSupport=true
真正容易被忽略的是驱动版本和框架配置
这个问题和 Oracle 版本、NLS 设置、时区都无关,纯属 JDBC 类型映射策略。只要代码里还混着 getDate() 或 setDate(),哪怕驱动升级到 ojdbc8,该丢还是丢。
- ojdbc6 默认把
DATE映射为java.sql.Timestamp;ojdbc8 默认又回退到java.sql.Date—— 升级驱动反而可能踩坑 - MyBatis 若没配
LocalDateTimeTypeHandler,或 JPA 没设hibernate.jdbc.time_zone,getObject()仍可能抛ClassCastException - 动态 SQL(如 NativeQuery)必须显式
addScalar("col", TimestampType),否则框架不知道你想要时间精度
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











