当前位置: 首页 > news >正文

为什么ORACLE使用JDBC查询SYSDATE时,RS.getDate能获取到时间部分?

  1. 这是个什问题?
    在某些版本ORACLE对应的JDBC驱动中,使用查询语句select sysdate from dual,使用rs.getDate获取到日期包含时间部分.而其他大部分数据库返回都不会包含时间部分.间接造成在做信创迁移时,造成时间部分丢失.

由于测试代码简单,这里不提供代码部分,直接测试Oracle mysql两种数据的情况,同时经过测试返现,对应的kingbase guassdb同样有一下情况

✅ [oracle] 数据库连接已建立
当前查询SQL:select sysdate from dual
Date类型值=>93
getDate_FMT => 2026-05-03 21:30:34
getDate=> 2026-05-03
getTimestamp=>2026-05-03 21:30:34.0
✅ [oracle] 数据库连接已关闭
✅ [mysql] 数据库连接已建立
当前查询SQL:select sysdate()
Date类型值=>93
getDate_FMT => 2026-05-03 00:00:00
getDate=> 2026-05-03
getTimestamp=>2026-05-03 21:30:34.0
✅ [mysql] 数据库连接已关闭

针对以上输出结果可以反应了以下信息:

ORACLE 和 MYSQL日期列对应的TYPE值都是 93
使用格式yyyy-MM-dd HH:mm:ss 格式化,可以发现ORACL包含时间部分21:30:34
当前的查询sql,复制到数据执行,不管是oracle还是mysql查询接口都包含了时间部分
以下是直接在mysql数据库执行的情况

sysdate()
2026-05-03 21:36:24
通过这些输出信息可以得到一个结论:数据库底层查询sysdate都是包含时间部分的,只是有些JDBC的驱动去掉了时间部分
  1. Oracle的JDBC驱动是如何处理的呢?
    带着上边的疑问,我分析了ojdbc8-19.7.0.0.jar的源码,找到对应的处理逻辑.由此发现,Oracle针对这种情况,还提供了专门的配置oracle.jdbc.DateZeroTime,让用户确定是否保留日期类型的时间部分

那这部分代码到底在哪里呢?以下是我定位到堆栈信息

T4CDateAccessor(DateTimeCommonAccessor).getDate(int) line: 135
T4CStatement(GeneratedStatement).getDate(long, int) line: 163
ForwardOnlyResultSet(GeneratedScrollableResultSet).getDate(int) line: 186
Multdbtest.testSysdate() line: 138
由此我们可以知道,Oralce处理日期的类是 DateTimeCommonAccessor

我们看下这部分代码

Date getDate(int paramInt, Calendar paramCalendar) throws SQLException {
Calendar calendar;
if (isNull(paramInt)) return null;
if (paramCalendar == null) {
calendar = this.statement.getDefaultCalendar();
} else {
calendar = (Calendar)paramCalendar.clone();
}
getBytesInternal(paramInt, this.tmpBytes);
int i = oracleYear(this.tmpBytes);
calendar.clear();
calendar.set(1, i);
calendar.set(2, oracleMonth(this.tmpBytes));
calendar.set(5, oracleDay(this.tmpBytes));
if (OracleDriver.getSystemPropertyDateZeroTime()) {
calendar.set(11, 0);
calendar.set(12, 0);
calendar.set(13, 0);
} else {
calendar.set(11, oracleHour(this.tmpBytes));
calendar.set(12, oracleMin(this.tmpBytes));
calendar.set(13, oracleSec(this.tmpBytes));
}
calendar.set(14, 0);
if (i > 0 && calendar.isSet(0)) {
calendar.set(0, 1);
}
return new Date(calendar.getTimeInMillis());
}

其中有一部分关键代码if (OracleDriver.getSystemPropertyDateZeroTime()) 如果这个值为true,就直接把时间部分值设置成0了,否则,就取数据返回的时间部分的信息.

那 OracleDriver.getSystemPropertyDateZeroTime 这个函数,从函数名基本可以知道它的意图,应该是获取 SystemProperty ,这些信息可以通过启动时注入.那我们推测是否是正确的呢?

public static boolean getSystemPropertyDateZeroTime() {
String str = PhysicalConnection.getSystemPropertyDateZeroTime(“false”);
return str.equalsIgnoreCase(“true”);
}
从这里代码只知道,可以大概推测到,这方法默认值返回的是false,就是要获取数据库返回的时间部分,我们继续往下追代码

static String getSystemPropertyDateZeroTime(String defaultValue) {
return getSystemProperty(“oracle.jdbc.DateZeroTime”, defaultValue);
}

private static String getSystemProperty(String configKey, String defaultValue) {
if (configKey != null) {
final String fstr = configKey;
final String fdefaultValue = defaultValue;
final String[] rets = { defaultValue };
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
rets[0] = System.getProperty(fstr, fdefaultValue);
return null;
}
});
return rets[0];
}
return defaultValue;
}

  1. 知道原因,那如何使用呢?
    目前知道时间部分存在的原因,如果目前希望rs.getDate返回的日期,跟其他数据库保一样不返回时间部分,就可以设置oracle.jdbc.DateZeroTime=true,对应测试代码如下:

String exesql = "select sysdate “;
if (dbName == “oracle”) {
exesql += " from dual”;
System.setProperty(“oracle.jdbc.DateZeroTime”, “true”);
}
4. MYSQL是如何处理的呢?
通过跟踪代码,数据也是返回了日期类型的,但是rs.getDate使用的是SqlDateValueFactory做了值转换,可以找到这个类,跟踪一下方法.

public Date localCreateFromDate(InternalDate idate) {
synchronized (this.cal) {
try {
if (idate.isZero()) {
throw new DataReadException(Messages.getString(“ResultSet.InvalidZeroDate”));
}

this.cal.clear(); this.cal.set(idate.getYear(), idate.getMonth() - 1, idate.getDay()); long ms = this.cal.getTimeInMillis(); return new Date(ms); } catch (IllegalArgumentException e) { throw ExceptionFactory.createException(WrongArgumentException.class, e.getMessage(), e); }

}
}
从以上代码可以知道,mysql只赋值了了年月日,对应调试的堆栈信息如下

SqlDateValueFactory.localCreateFromDate(InternalDate) line: 80
SqlDateValueFactory.localCreateFromDate(InternalDate) line: 50
SqlDateValueFactory(AbstractDateTimeValueFactory).createFromDate(InternalDate) line: 67
SqlDateValueFactory.localCreateFromTimestamp(InternalTimestamp) line: 120
SqlDateValueFactory.localCreateFromTimestamp(InternalTimestamp) line: 50
SqlDateValueFactory(AbstractDateTimeValueFactory).createFromTimestamp(InternalTimestamp) line: 87
MysqlTextValueDecoder.decodeTimestamp(byte[], int, int, ValueFactory) line: 79
ByteArrayRow(AbstractResultsetRow).decodeAndCreateReturnValue(int, byte[], int, int, ValueFactory) line: 87
ByteArrayRow(AbstractResultsetRow).getValueFromBytes(int, byte[], int, int, ValueFactory) line: 241
ByteArrayRow.getValue(int, ValueFactory) line: 91
ResultSetImpl.getDate(int) line: 740
5. 信创总结
在适配ORACLE数据信创时,由于oracle返回了日期时间的部分.导致迁移到其他数据库时,返回前端的JSON日期串,时间部分丢失了.此时要做信创适配,有一下三种途径

修改业务代码,需要显示时间的代码,统一调整成rs.getTimestamp

http://www.jsqmd.com/news/1217794/

相关文章:

  • 浪琴中国官方售后服务中心|全新电话和完整地址权威信息公告(2026年7月最新) - 浪琴服务中心
  • OpenCV C++数据类型转换实战:Mat、指针与vector互转详解
  • Poppins字体:如何用一款开源字体实现印地语与拉丁语的无缝排版?
  • Superset集成指南:从原理到企业级实践
  • 游戏资源获取全攻略:如何高效白嫖钻石与优化游戏体验
  • 向量引擎工具入口验收:夜渡城为什么先问十道门
  • 为什么你的AI Agent AB测试总跑不出p<0.01?——埋点偏差、状态漂移、Agent记忆污染三大隐性杀手全曝光
  • 低代码财务系统怎么样?从开发者的实战视角剖析技术选型
  • 抖音无水印视频批量下载终极指南:5分钟快速上手
  • Unity C#热修复实战:InjectFix原理、工作流与避坑指南
  • 毕设项目 深度学习图像风格迁移系统(源码分享)
  • AM62L CBASS防火墙配置实战:从原理到代码实现
  • 基于AM437x与PRU-ICSS的工业级隔离式电流电压测量系统设计
  • 2026年7月最新北京浪琴官方售后客户服务电话及线下网点地址 - 浪琴官方售后服务中心
  • Android开发:RecyclerView与CardView实战指南
  • C++网络编程:IPv4地址整数与字符串转换的实现与优化
  • JavaMail邮件发送实战:从基础配置到高级应用
  • 从MiniMax创始人预告看AI模型迭代:如何科学评估M3与Hailuo 3更新
  • CUDA C++编程核心:从语言特性到GPU高性能计算实践
  • C/C++调用Java:JNI原理、实战与性能优化指南
  • 深入解析IVA2.2 DMA编程模型:硬件触发、QDMA与IDMA实战指南
  • RocketMQ 5.x 的定时消息新特性(基于时间轮的精准定时)
  • 欧米茄官方售后服务中心服务热线及具体地址实地考察报告_多信源验证(2026年7月更新) - 欧米茄服务中心
  • Android定时任务实现:AlarmManager详解与优化
  • VC++录音机开发实战:从Waveform API到MP3编码与系统音频录制
  • 服务器电源架构解析:从PFC到LLC谐振变换的可靠性设计
  • Flask项目创建与部署全指南:从基础到生产环境
  • Intelligent Lux:智能引导式EDA工作流重构
  • 补充描述:IEC 61850 中 ICD、CID、SCL、SCD、IID 的关系说明
  • Android屏幕适配全攻略:从dp到折叠屏