MyBatis时间区间查询异常排查(达梦数据库)

一、问题

1.1、版本

  • JDK 版本:JDK 17 (龙井JDK)
  • Spring Boot 版本:Spring Boot 3.3.0
  • MyBatis / MyBatis-Plus 版本:MyBatis-Plus 3.5.16,使用的是 mybatis-plus-spring-boot3-starter(专门适配 Spring Boot 3)。同时引入了 mybatis-plus-jsqlparser(用于 SQL 解析和分页等功能)。
  • 达梦数据库驱动: 8.1.3.140

1.2、问题

  • mybatis 时间区间查询,查出异常数据
  • mybatis的SQL以及 查询出的数据,很明显,时间区间有问题
sql 复制代码
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b5825b6] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@2137505285 wrapping dm.jdbc.driver.DmdbConnection@281d9254] will not be managed by Spring
==>  Preparing: SELECT id, device_id, day_time, failure, create_time, update_time, deleted FROM tb_failure WHERE deleted = 0 AND ( device_id = ? AND day_time BETWEEN ? AND ? ) ORDER BY device_id ASC, day_time ASC
==> Parameters: 1(String), 2026-04-01 00:00:00.0(Timestamp), 2026-04-30 23:59:59.999999999(Timestamp)
<==    Columns: id, device_id, day_time, failure, create_time, update_time, deleted
<==        Row: 57, 1, 2026-05-01 00:00:00.000000, 0.0, 2026-05-25 18:03:40.677000, 2026-05-25 18:03:40.677000, 0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7b5825b6]


-- 改成这样也不行
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74b53705] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@76633552 wrapping dm.jdbc.driver.DmdbConnection@69b5bb66] will not be managed by Spring
==>  Preparing: SELECT id, device_id, day_time, failure, create_time, update_time, deleted FROM tb_failure WHERE deleted = 0 AND ( device_id = ? AND (day_time > = ? AND day_time <= ?) ) ORDER BY device_id ASC, day_time ASC
==> Parameters: 1(String), 2026-04-01 00:00:00.0(Timestamp), 2026-04-30 23:59:59.999999999(Timestamp)
<==    Columns: id, device_id, day_time, failure, create_time, update_time, deleted
<==        Row: 57, 1, 2026-05-01 00:00:00.000000, 0.0, 2026-05-25 18:03:40.677000, 2026-05-25 18:03:40.677000, 0
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@74b53705]
  • 执行SQL就可以,可能是客户端处理了
sql 复制代码
SELECT id, device_id, day_time, failure, create_time, update_time, deleted FROM 
tb_failure WHERE deleted = 0 AND ( device_id = 1 AND day_time BETWEEN '2026-04-01 00:00:00.0' AND '2026-04-30 23:59:59.999999999' ) ORDER BY device_id ASC, day_time ASC

二、解决

2.1、问题分析

  • 差异点:MyBatis 日志显示参数 day_time BETWEEN ? AND ? 的结束值是 2026-04-30 23:59:59.999999999(9位纳秒),但实际返回了 2026-05-01 00:00:00.000000 的数据。
  • 根本原因:
    • 精度上限:达梦数据库的 TIMESTAMP 类型最大只支持 6 位小数秒精度(微秒级) 。你传入的 999999999 纳秒(即9位)超出了其处理能力。
    • 驱动行为:达梦JDBC驱动在将JavaTimestamp对象(可能携带纳秒精度)发送给数据库前,可能将超出部分(9位 -> 6位)进行了四舍五入处理。
    • 溢出推论:999999999 纳秒四舍五入到微秒(6位)后,无限接近下一秒的 000000。再加上达梦内部的时间比较逻辑,导致条件 <= '2026-04-30 23:59:59.999999' 实际被当作 <= '2026-05-01 00:00:00' 处理,从而拉取了5月1日的数据。

2.2、解决思路

  • 调整代码逻辑,避免使用"23:59:59..." :这是最稳健的做法,绕开了精度问题。
    • 思路:查询4月份数据时,范围定为 day_time >= '2026-04-01'day_time < '2026-05-01'
    • 优点:逻辑清晰,完全不受秒精度影响,且能正确处理索引。
  • 显式截断参数精度(如果无法修改业务逻辑):如果你必须使用"月末最后一刻"的写法,可以在传入MyBatis之前,手动将Timestamp对象的纳秒部分截断,使其符合达梦的6位微秒精度。
相关推荐
我不是程序员三三3 小时前
如何监控电脑|企业终端行为监控概念科普与落地方法论
数据库·电脑·php
lhldsg4 小时前
全民健身解决方案软件开发实战:从架构设计到部署指南
java·前端·数据库·小程序
我是大猴子4 小时前
线上耗时问题排查
数据库
小码过河.4 小时前
oceanbase中zone和observer、分区表之间关系
前端·数据库·oceanbase
其实防守也摸鱼5 小时前
OpenClaw Windows 踩坑实战指南
运维·服务器·数据库·windows·github·copilot
SelectDB5 小时前
Apache Doris+ Paimon 2.0:构建 Agentic AI 数据闭环
大数据·数据库·数据分析
麦聪聊数据5 小时前
全链路数据安全防护(中):入口、权限、审计,筑牢安全管控铁三角
数据库
山岚的运维笔记5 小时前
mysql 专业笔记 -- 第 17 章:连接:连接三个具有相同名称 ID 的表
运维·数据库·笔记·后端·学习·mysql·dba
YangYang9YangYan5 小时前
校招视角|财务数字化岗位 SQL、工具、项目完整备考指南
大数据·数据库·sql
bksczm5 小时前
从 “什么是 MySQL“ 到库与表的完整操作(MySQL基础篇)
linux·数据库·mysql