开发者

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

开发者 https://www.devze.com 2025-04-29 10:19 出处:网络 作者: 爱的叹息
目录1. MyBATis 插件基础2. 插件开发示例2.1. 自定义插件类2.2. 配置插件2.3. 测试插件3. 核心使用场景3.1. 日志记录3.2. SQL 修改3.3. 参数处理3.4. 结果集处理4. 表格整理总结5. 最佳实践建议
目录
  • 1. MyBATis 插件基础
  • 2. 插件开发示例
    • 2.1. 自定义插件类
    • 2.2. 配置插件
    • 2.3. 测试插件
  • 3. 核心使用场景
    • 3.1. 日志记录
    • 3.2. SQL 修改
    • 3.3. 参数处理
    • 3.4. 结果集处理
  • 4. 表格整理总结
    • 5. 最佳实践建议

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

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

      1. MyBatis 插件基础

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

      • ExecutorupdatequeryflushStatementscommitrollbackgetTransactioncloseisClosed
      • ParameterHandlergetParameterObjectsetParameters
      • ResultSetHandlerhandleResultSetshandleCursorResultSetshandleOutputParameters
      • StatementHandlerprepareparameterizebatchupdatequery

      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.ut编程客栈il.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>
          <!-- 配置插件 -->
          <pphplugins>
              <FSUledw;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.pythongetMapper(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修改或优化 SQLhttp://www.devze.com 语句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 的核心功能。
      • 谨慎修改 SQL:修改 SQL 时要确保语法正确,避免引入潜在的 SQL 注入风险。
      • 合理使用属性:通过 setProperties 方法为插件设置属性,增强灵活性。
      • 单元测试:编写单元测试验证插件功能,确保其在各种场景下的稳定性。
      • 文档记录:详细记录插件的使用方法和注意事项,便于团队成员理解和维护。

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

      到此这篇关于MyBatis插件开发的完整详细例子的文章就介绍到这了,更多相关MyBatis插件开发内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号