Mybatis XML文件中,对java.util.Date对象的值到转换为执行SQL进行比较所做的隐式行为分析。

本次分析了mybatis的mapper XML文件,sql的where子句中使用java.util.Date进行比较进行分析。

假设使用的是以下sql语句。

select * from xxx where create_time > '2024-06-20 20:38:38'

在mybatis中,会将java.util.Date对象的值转为java.sql.Timestamp,之后在mybatis取值的时候,会调用java.sql.Timestamp.toString()方法获取字符串值(也就是'2024-06-20 20:38:38')。
带有日期对比字符串的sql通过jdbc传到MySQL服务器端,此时,mysql会怎么处理这种对比呢?答案就是**字符串会隐式的转换create_time 值所代表的MySQL类型,之后进行对比。


分析只关注核心位置,不对整个流程进行分析(你断点此位置一般就能看到)。

下面就着重分析**Mybatis的XML文件,对java.util.Date类型的处理方式是怎样的?

首先进入到org.apache.ibatis.type.DateTypeHandler#setNonNullParameter方法,这里没什么说明的。

org.apache.ibatis.logging.jdbc.PreparedStatementLogger#invoke方法中,
我们会看到SET_METHODS方法是个Set集合。
SET_METHODS方法的值列表
核心位置

经过debug,我们会进到org.apache.ibatis.logging.jdbc.BaseJdbcLogger类的位置。

getParameterValueString方法用于打印输出值和值的类型。


这一行是关键语句return method.invoke(statement, params);
接着进入这行代码,会执行到com.alibaba.druid.pool.DruidPooledPreparedStatement#setTimestamp(int, java.sql.Timestamp)

在debug进入 stmt.setTimestamp(parameterIndex, x);


会到com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl#setTimestamp(int, java.sql.Timestamp)方法位置处,这里的选中这一行chain.preparedStatement_setTimestamp(this, parameterIndex, x);是核心,


之后会到com.mysql.cj.jdbc.ClientPreparedStatement#setTimestamp(int, java.sql.Timestamp)方法位置处。


最后会到com.mysql.cj.NativeQueryBindings#setTimestamp,这里就是给PreparedStatement对象的sql占位符绑定值得位置了。
可以看到,到最后这个值还是java.sql.Timestamp类型的。

至于PreparedStatement之后怎么处理我觉的就可以不用关注了,因为PreparedStatement配套的提供了setTimestamp方法,就说明内部已有支持的转换方式,而且MySQL驱动本身自身也支持setTimestamp。

MySQL官方文档的对于DATETIME和TIMESTAMP类型进行对比的资料。

https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html

https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html

如果其中一个参数是 TIMESTAMP 或 DATETIME 列,而另一个参数是常量,那么在进行比较之前,会将常量转换为时间戳。这样做是为了对 ODBC 更友好。但 IN() 的参数不会这样做。为了安全起见,在进行比较时应始终使用完整的日期时间、日期或时间字符串。例如,在使用带有日期或时间值的 BETWEEN 时,为了获得最佳结果,应使用 CAST() 将值明确转换为所需的数据类型。

来自一个或多个表的单行子查询不视为常量。例如,如果子查询返回一个要与 DATETIME 值比较的整数,那么比较将以两个整数的形式进行。整数不会转换为时间值。要将操作数作为 DATETIME 值进行比较,请使用 CAST() 将子查询值显式转换为 DATETIME 值。

其他资料

MySQL关于日期格式化的相关函数。
CAST转换类型
The DATE, DATETIME, and TIMESTAMP Types

posted @ 2024-06-21 11:08  星小梦  阅读(31)  评论(0编辑  收藏  举报