DATE_FORMAT
是 SQL 函数,主要用于将日期/时间类型的字段按照指定格式转换成字符串。在 MyBatis 的 XML 动态 SQL 中,你看到的这段代码是为了比较数据库中的日期字段和传入参数的日期值,但会忽略时间部分,只比较年月日。
代码解释
<if test="closeDate != null and closeDate != ''">
AND DATE_FORMAT(close_date, '%Y-%m-%d') = DATE_FORMAT(#{closeDate}, '%Y-%m-%d')
</if>
-
DATE_FORMAT(close_date, '%Y-%m-%d')
• 将数据库中的close_date
字段(假设是DATETIME
或TIMESTAMP
类型)格式化成年-月-日
的字符串(例如2023-10-05
),忽略时间部分。 -
DATE_FORMAT(#{closeDate}, '%Y-%m-%d')
• 将传入的参数closeDate
也格式化成年-月-日
的字符串,确保两者格式一致。 -
AND ... = ...
• 比较格式化后的字符串,实现“仅按日期比较,忽略时间”的效果。
为什么需要这么做?
• 场景:假设数据库中的 close_date
是 DATETIME
类型(例如 2023-10-05 14:30:00
),而传入的 closeDate
参数可能是一个带时间的日期(例如 2023-10-05 08:15:00
),直接比较会导致不匹配。
• 解决:通过格式化将两者的时间部分去掉,只比较日期部分(2023-10-05
)。
参数 closeDate
的常见类型
-
Java 中的
Date
类型
• 如果closeDate
是java.util.Date
,MyBatis 会将其转为数据库的DATETIME
类型,再调用DATE_FORMAT
。 -
字符串类型
• 如果closeDate
是字符串(如"2023-10-05"
),DATE_FORMAT
会尝试将其解析为日期,再格式化。但需确保字符串格式与数据库兼容(例如yyyy-MM-dd
)。
潜在问题
-
性能影响
• 对数据库字段close_date
使用DATE_FORMAT
会导致索引失效(因为字段被函数处理后比较),大数据量时可能影响性能。• 改进方案:改用范围查询(如
close_date BETWEEN '2023-10-05 00:00:00' AND '2023-10-05 23:59:59'
)。 -
时区问题
• 如果数据库和应用程序的时区不同,格式化后的日期可能不一致,需要确保时区统一。
其他替代方案(推荐)
如果使用 MySQL,可以用 DATE()
函数直接提取日期部分:
AND DATE(close_date) = DATE(#{closeDate})
• 更简洁,但同样有索引失效问题。
总结
• 目的:比较日期部分,忽略时间。
• 代价:可能影响性能,需根据数据量权衡。
• 最佳实践:如果允许,尽量用数据库的日期范围查询(如 BETWEEN
)。