概览
MyBatis的SQL输出日志语句和参数是分开打印的,我们调试时需要将语句和参数再次拼接才能进行测试执行。当遇到长SQL和参数较多时,还原一个SQL往往需要十几分钟的时间。有很多优秀(懒)的程序员通过编写集成开发环境插件的方式来优化SQL还原拼接的过程,例如Idea平台下的: mybatis-log-plugin(收费)、mybatis-log-free(免费)。
最近接到的项目有很多长SQL并且参数的数量也很多,在做SQL优化时需要花很多时间在SQL拼接上,想到前同事使用MyBatis框架插件机制来打印完整的SQL日志,尝试自己实现一下,同时也是为了加强对MyBatis框架的了解。
MyBatis Plugins
MyBatis的插件机制更准确的说是拦截器,可以用来拦截执行SQL语句执行之前或之后的操作,从而实现对 SQL 执行过程的干预。例如:参数加解密、权限判断、统一字段处理、添加分页、记录SQL执行时间等功能。实现MyBatis插件非常简单,写一个实现Interceptor接口的类,并通过@Intercepts、@Signature注解描述自己拦截的行为即可。
示例-1
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;
// 拦截所有的 update 方法调用
@Intercepts(
{
@Signature(type= Executor.class, method = "update", args = {
MappedStatement.class,Object.class})
})
public class ExamplePlugin implements Interceptor {
private Properties properties = new Properties();
@Override
public Object intercept(Invocation invocation) throws Throwable {
// TODO 执行之前的业务处理(自定义)
Object returnObject = invocation.proceed();
// TODO 执行之后的业务处理(自定义)
return returnObject;
}
/**
* 设置插件参数,内容可以在mybatis-config.xml中设置
*/
@Override
public void setProperties(Properties properties) {
this.properties = properties;
}
}
Invocation
Invocation象包含了被拦截方法的所有必要信息,Target(被调用的对象),Method(被调用的方法),Arguments(传递给方法的参数列表)。proceed 方法用于继续执行被拦截的方法。如果不调用 proceed 方法,被拦截的方法将不会被执行。
MappedStatement
MappedStatement是MyBatis中的一个核心概念和内部类,它是MyBatis执行SQL语句的关键对象。每个MappedStatement对象代表了一个已经映射的SQL语句,包括了执行此SQL语句所需的所有信息,如SQL语句文本、参数映射、结果映射、缓存策略等
MappedStatement对象由MyBatis的内部机制自动创建并管理的。当用户定义了一个Mapper接口中的方法或者XML映射文件中的SQL语句时,MyBatis会根据这些定义生成相应的MappedStatement对象,并将其存储在Configuration对象的内部映射表中。
Configuration
Configuration创建和管理MappedStatement对象,是MyBatis的核心配置对象,包含了所有映射信息、类型别名、类型处理器、对象工厂等配置。
BoundSql
BoundSql代表一个已绑定参数的SQL语句。由SqlSource创建,SqlSource是MyBatis中用于解析SQL语句并创建BoundSql的抽象类,当执行一个MappedStatement时,MyBatis会根据MappedStatement中的SqlSource创建一个BoundSql实例。BoundSql包含了SQL语句文本、参数列表以及参数映射等信息。
MetaObject
MetaObject是一个重要工具类,它主要用于简化JavaBean的操作,提供了一种统一的方式来访问和操作对象的属性。
完整示例
import org.apache.commons.collections4.CollectionUtils;
import org