时间类型格式化问题踩坑

记一次时间类型格式化问题:Hutools DbUtil 拼接 SQL 时如何避免日期精度丢失?

一、问题背景

在一次上游服务 SDK 开发中,我们需要通过 Hutools 工具包中的 DbUtil 实现数据持久化。在拼接 SQL 更新语句时,遇到了一个隐蔽的日期格式化问题。核心代码如下:

java 复制代码
Entity.create("table_name")
      .set("start_time", "<= " + xxx.getDate()) // 直接拼接日期对象
      .set("end_time", "IS NULL"));

其中 xxx.getDate() 对应实体类的字段定义如下:

java 复制代码
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8")
private Date date; // 期望保留毫秒精度

问题现象

数据库记录中的 start_time 字段丢失了毫秒(SSS)精度,导致时间范围查询出现误差。


二、问题分析

1. 为什么会出现精度丢失?

  • 直接字符串拼接xxx.getDate() 返回 java.util.Date 对象,调用 toString() 方法时默认格式为 EEE MMM dd HH:mm:ss zzz yyyy不包含毫秒信息
  • 注解作用范围@JsonFormat 仅在 Jackson 序列化/反序列化 JSON 时生效,不影响 Date.toString() 的行为。

2. 错误示例分析

java 复制代码
// 假设 date 值为 2023-10-01 12:34:56.789
String sql = "<= " + date.toString();
// 实际拼接结果:<= Sat Oct 01 12:34:56 CST 2023

三、解决方案

1. 手动格式化日期(基础版)

通过 SimpleDateFormat 指定包含毫秒的格式:

java 复制代码
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String formattedDate = sdf.format(xxx.getDate());

Entity.create("table_name")
      .set("start_time", "<= '" + formattedDate + "'") // 注意添加引号

2. 使用 Hutools 工具类(推荐)

利用 DateUtil.format() 简化操作,避免重复造轮子:

java 复制代码
import cn.hutool.core.date.DateUtil;

String formattedDate = DateUtil.format(xxx.getDate(), "yyyy-MM-dd HH:mm:ss.SSS");

Entity.create("table_name")
      .set("start_time", "<= '" + formattedDate + "'")

四、避坑指南

1. SQL 注入风险

直接拼接字符串存在安全隐患,建议改用 预编译占位符

java 复制代码
// 使用 Hutools 的预编译方式
Entity entity = Entity.create("table_name")
                     .set("start_time", new Condition("<= ?", formattedDate));

2. 时区一致性

确保数据库连接时区与 @JsonFormatGMT+8 一致,避免时差问题。


五、总结

关键点 说明
Date.toString() 默认不包含毫秒,不可依赖其生成 SQL 字符串
@JsonFormat 局限 仅作用于 JSON 序列化,不影响其他场景的日期格式
手动格式化 使用 SimpleDateFormat 或 Hutools 工具类指定明确格式
安全拼接 优先使用预编译语句,避免拼接字符串带来的 SQL 注入风险

最佳实践

  • 始终通过 显式格式化 控制日期字符串的输出。
  • 涉及时间比较时,确保数据库字段类型与精度(如 DATETIME(3))和代码格式一致。
相关推荐
FG.10 分钟前
Day13
java·面试
我爱Jack1 小时前
ObjectMapper 在 Spring 统一响应处理中的作用详解
java·开发语言
捡田螺的小男孩1 小时前
京东一面:接口性能优化,有哪些经验和手段
java·后端·面试
小白杨树树1 小时前
【SSM】SpringMVC学习笔记8:拦截器
java·开发语言
艾露z1 小时前
深度解析Mysql中MVCC的工作机制
java·数据库·后端·mysql
冷心笑看丽美人1 小时前
Spring MVC 之 异常处理
java·开发语言·java-ee·spring mvc
神仙别闹1 小时前
基于Java(SpringBoot、Mybatis、SpringMvc)+MySQL实现(Web)小二结账系统
java·spring boot·mybatis
超级小忍1 小时前
Java集合中Stream流的使用
java·开发语言
趁你还年轻_2 小时前
Spring 官方推荐构造函数注入
java·spring·log4j