java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > MyBatis插件开发

MyBatis插件开发的完整详细例子(附注释和总结)

作者:爱的叹息

这篇文章主要介绍了MyBatis插件开发的完整详细例子,通过示例代码和详细注释,展示了如何在不同接口和方法中实现自定义逻辑,如日志记录、SQL修改、参数处理和结果集处理,文中给出了详细的代码示例,需要的朋友可以参考下

在这里插入图片描述

MyBatis 插件(Interceptor)允许开发者在已映射语句执行过程中的某一点进行拦截调用,从而实现自定义逻辑。以下是一个完整的 MyBatis 插件开发示例,涵盖所有使用场景,并附有详细注释和总结。

1. MyBatis 插件基础

MyBatis 允许拦截以下接口的方法:

2. 插件开发示例

2.1. 自定义插件类

创建一个自定义插件类 MyPlugin,该插件将拦截 Executor 的 query 方法和 StatementHandler 的 prepare 方法。

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.statement.StatementHandler;

import java.sql.Connection;
import java.sql.Statement;
import java.util.Properties;

@Intercepts({
    @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取被拦截方法的参数
        Object[] args = invocation.getArgs();

        // 拦截 Executor.query 方法
        if (invocation.getTarget() instanceof Executor) {
            MappedStatement ms = (MappedStatement) args[0];
            Object parameter = args[1];
            RowBounds rowBounds = (RowBounds) args[2];
            ResultHandler resultHandler = (ResultHandler) args[3];

            BoundSql boundSql = ms.getBoundSql(parameter);
            String sql = boundSql.getSql();
            System.out.println("Executing SQL: " + sql);

            // 执行原方法
            return invocation.proceed();
        }

        // 拦截 StatementHandler.prepare 方法
        if (invocation.getTarget() instanceof StatementHandler) {
            StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
            Connection connection = (Connection) args[0];
            Integer integer = (Integer) args[1];

            // 获取原始 SQL
            BoundSql boundSql = statementHandler.getBoundSql();
            String originalSql = boundSql.getSql();
            System.out.println("Original SQL: " + originalSql);

            // 修改 SQL(例如添加注释)
            String newSql = "/* MyPlugin */ " + originalSql;
            BoundSql newBoundSql = new BoundSql(
                boundSql.getMappedStatement().getConfiguration(),
                newSql,
                boundSql.getParameterMappings(),
                boundSql.getParameterObject()
            );
            MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
            metaObject.setValue("delegate.boundSql", newBoundSql);

            // 执行原方法
            return invocation.proceed();
        }

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        // 使用 Plugin.wrap 包装目标对象
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 设置插件属性(可选)
    }
}

2.2. 配置插件

在 mybatis-config.xml 中配置自定义插件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置插件 -->
    <plugins>
        <plugin interceptor="com.example.plugin.MyPlugin">
            <!-- 可以设置插件属性 -->
            <!-- <property name="propertyName" value="propertyValue"/> -->
        </plugin>
    </plugins>

    <!-- 其他配置... -->
</configuration>

2.3. 测试插件

编写测试代码来验证插件的功能:

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.Reader;

public class PluginTest {
    public static void main(String[] args) throws Exception {
        // 读取 MyBatis 配置文件
        Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

        try (SqlSession session = sqlSessionFactory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);

            // 执行查询操作,触发插件拦截
            User user = mapper.selectUserById(1L);
            System.out.println("User: " + user.getName());
        }
    }
}

3. 核心使用场景

3.1. 日志记录

在 Executor 的 query 和 update 方法中添加日志记录,便于调试和监控。

3.2. SQL 修改

在 StatementHandler 的 prepare 方法中修改 SQL 语句,例如添加统一的注释或进行性能优化。

3.3. 参数处理

在 ParameterHandler 的 setParameters 方法中对参数进行预处理,如加密、格式化等。

3.4. 结果集处理

在 ResultSetHandler 的 handleResultSets 方法中对结果集进行后处理,如数据脱敏、缓存等。

4. 表格整理总结

场景拦截接口及方法具体应用示例代码片段
日志记录Executor.queryExecutor.update在执行 SQL 前后记录日志System.out.println("Executing SQL: " + sql);
SQL 修改StatementHandler.prepare修改或优化 SQL 语句String newSql = "/* MyPlugin */ " + originalSql;
参数处理ParameterHandler.setParameters对参数进行预处理(如加密)preparedStatement.setString(1, encrypt(parameter));
结果集处理ResultSetHandler.handleResultSets对查询结果进行后处理(如脱敏)resultList.forEach(item -> item.setEmail(maskEmail(item.getEmail())));
性能监控Executor.queryExecutor.update记录 SQL 执行时间long startTime = System.currentTimeMillis(); ... long endTime = ...
分页支持StatementHandler.parameterize动态添加分页参数preparedStatement.setInt(1, offset); preparedStatement.setInt(2, limit);

5. 最佳实践建议

通过以上示例和总结,可以全面掌握 MyBatis 插件的开发和应用场景。

到此这篇关于MyBatis插件开发的完整详细例子的文章就介绍到这了,更多相关MyBatis插件开发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文