首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >升级Oracle导致Java程序日期截断的场景

升级Oracle导致Java程序日期截断的场景

作者头像
bisal
发布2025-07-24 17:15:14
发布2025-07-24 17:15:14
13700
代码可运行
举报
运行总次数:0
代码可运行

同事碰到个问题,他们的数据库从Oracle 11g升级到Oracle 19c,对应Java代码要将jdbc驱动从ojdbc14.jar升级到ojdbc7.jar,发现一个date参数的问题。

(1)ojdbc14.jar:DATE > java.sql.Date,转换后不带时分秒(时分秒是0:0:0)。

(2)ojdbc6.jar及之后版本:DATE > java.sql.Timestamp 转换后带时分秒。

这就导致查询数据可能会出现问题,原来存储的日期数据格式是"2025-01-01",之前程序检索时,会使用"2025-01-01",可以找到数据,但现在用的是"2025-01-01 01:00:00"进行查找,多了时分秒自然查询为空。

如果是改程序,需要做的,就是将一个时分秒是0的参数传给Oracle,例如SimpleDateFormat("yyyy-MM-dd")。如果改SQL,可以利用trunc()函数,对时间进行截断,select ... where cdate = trunc(:1)。

但是因为这个系统有几十个微服务,SQL很多,如果一个一个改,工作量很大,还得每个业务逻辑都要排查,对方要求最好能通过配置解决,不改动Java的代码。

他们尝试了向配置中增加V8Compatible和mapdatetotimestamp,但是没生效,

代码语言:javascript
代码运行次数:0
运行
复制
<property name="connectionProperties" value="config.decrypt=true;config.decrypt.key=${jdbc_publicKey};oracle.jdbc.V8Compatible=true"/>
<property name="connectionProperties" value="config.decrypt=true;config.decrypt.key=${jdbc_publicKey};oracle.jdbc.mapdatetotimestamp=false"/>

V8Compatibl参数看名字,就能猜到是为了做到兼容的,但是从文档看,应该是个过时的,可能得确认什么版本可用,

https://docs.oracle.com/en/database/oracle/oracle-database/23/jjdbc/JDBC-reference-information.html#GUID-FCB7E652-4532-47AF-9783-B7E2B6ADA41C

mapdatetotimestamp参数作用是可以设置Date数据类型格式,默认包含时分秒的信息,设置为false,则只显示日期部分。

但是通过打断点,看到配置的参数是生效的,但是执行结果跟预期不一致。

还能怎么解决?

通过检索资料,MyBatis提供了使用自定义TypeHandler转换类型的功能,可以自己写个TypeHandler来对 DATE 类型做特殊处理:

代码语言:javascript
代码运行次数:0
运行
复制
/\*\*
 \* Welcome to https://waylau.com
 \*/
package com.waylau.lite.mall.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.Date;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

/\*\*
 \* 自定义TypeHandler,用于将日期转为'yyyy-MM-dd'
 \* 
 \* @since 1.0.0 2018年10月10日
 \* @author <a href="https://waylau.com">Way Lau</a>
 \*/
@MappedJdbcTypes(JdbcType.DATE)
@MappedTypes(Date.class)
public class DateShortTypeHandler extends BaseTypeHandler<Date> {

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType)
			throws SQLException {
		DateFormat df = DateFormat.getDateInstance();
		String dateStr = df.format(parameter);
		ps.setDate(i, java.sql.Date.valueOf(dateStr));
	}

	@Override
	public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
		java.sql.Date sqlDate = rs.getDate(columnName);
		if (sqlDate != null) {
			return new Date(sqlDate.getTime());
		}
		return null;
	}

	@Override
	public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		java.sql.Date sqlDate = rs.getDate(columnIndex);
		if (sqlDate != null) {
			return new Date(sqlDate.getTime());
		}
		return null;
	}

	@Override
	public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		java.sql.Date sqlDate = cs.getDate(columnIndex);
		if (sqlDate != null) {
			return new Date(sqlDate.getTime());
		}
		return null;
	}

}

如果是Spring项目,以下面方式进行TypeHandler的配置:

代码语言:javascript
代码运行次数:0
运行
复制
<!-- 自定义 -->
<!--声明TypeHandler bean-->
<bean id="dateShortTypeHandler" class="com.waylau.lite.mall.type.DateShortTypeHandler"/>

<!-- MyBatis 工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />

	<!--TypeHandler注入-->
	<property name="typeHandlers" ref="dateShortTypeHandler"/>
</bean>
如何使用TypeHandler?
方式1:指定jdbcType为DATE

例如,目前,项目中有如下的字段,是采用的DATE类型:

代码语言:javascript
代码运行次数:0
运行
复制
birthday = #{birthday, jdbcType=DATE},
方式2:指定typeHandler
指定typeHandler为我们自定义的TypeHandler:
代码语言:javascript
代码运行次数:0
运行
复制
birthday = #{birthday, typeHandler=com.waylau.lite.mall.type.DateShortTypeHandler},

经过测试,这种方案可行,其实就是在MyBatis传递参数时,对日期进行截断,相当于重写了jdbcType=Date和java.util.date中间传参转换的逻辑,达到了只用时分秒的效果。

针对这个问题,涉及到的还是日期字段的规范使用,究竟存储yyyy-mm-dd,还是yyyy-mm-dd hh24:mi:ss,要结合具体场景,选择合适的方案,当然,对代码的管理,更是很重要,否则一旦核心的开发人员变更,这段code谁都不敢改,就只能石沉大海,不能扩展,不能调整,无论是使用,还是运维,都会带来风险。

参考资料:

https://blog.csdn.net/2501_90255767/article/details/145217993

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 bisal的个人杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何使用TypeHandler?
  • 方式1:指定jdbcType为DATE
    • 方式2:指定typeHandler
    • 指定typeHandler为我们自定义的TypeHandler:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档