MyBatis Plus 是 MyBatis 的增强工具,提供了许多便捷的功能来简化开发,其中插件机制是其重要的扩展点之一。InnerInterceptor 是 MyBatis Plus 3.x 中用于实现插件拦截的一个核心接口,允许开发者自定义拦截逻辑,比如修改 SQL、设置参数或处理结果集。
![图片[1]_MyBatis Plus InnerInterceptor 深度解析:自定义拦截器实战_知途无界](https://zhituwujie.com/wp-content/uploads/2025/03/d2b5ca33bd20250317100112.png)
以下是关于 InnerInterceptor 的实现和使用方式的详细讲解。
一、InnerInterceptor 简介
InnerInterceptor 是 MyBatis Plus 提供的一个拦截器接口,主要用于在 SQL 执行的不同阶段插入自定义逻辑。与 MyBatis 的 Interceptor 类似,但更贴合 MyBatis Plus 的设计理念,通常用于分页、多租户、动态表名等场景。
常见的 InnerInterceptor 实现包括:
- 分页插件(
PaginationInnerInterceptor) - 多租户插件(
TenantLineInnerInterceptor) - 动态表名插件(
DynamicTableNameInnerInterceptor)
二、InnerInterceptor 的核心方法
InnerInterceptor 接口定义了以下核心方法:
public interface InnerInterceptor {
/**
* 在执行 SQL 之前拦截
*/
boolean beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout);
/**
* 在执行查询之前拦截(针对 SELECT 语句)
*/
void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
/**
* 在更新操作(INSERT/UPDATE/DELETE)之前拦截
*/
void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException;
/**
* 在 SQL 执行完成后拦截
*/
void afterQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql, List<Object> resultList) throws SQLException;
/**
* 清理资源(可选实现)
*/
void clearLocalCache();
}
开发者可以根据需求实现其中的方法,在 SQL 执行的各个阶段插入自定义逻辑。
三、自定义 InnerInterceptor 实现
以下是一个简单的自定义 InnerInterceptor 示例,用于记录 SQL 执行时间:
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public class SqlExecutionTimeInterceptor implements InnerInterceptor {
@Override
public boolean beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
long startTime = System.currentTimeMillis();
// 可以通过 ThreadLocal 或其他方式存储开始时间
System.out.println("SQL Preparation Start...");
// 模拟在 StatementHandler 中设置属性(可选)
return true; // 返回 true 表示继续执行,false 表示中断
}
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
System.out.println("Executing Query: " + boundSql.getSql());
}
@Override
public void afterQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql, List<Object> resultList) throws SQLException {
long endTime = System.currentTimeMillis();
System.out.println("SQL Execution Time: " + (endTime - (System.currentTimeMillis() - /* 假设获取开始时间 */ 1000)) + "ms");
// 注意:实际实现中需要合理管理开始时间(如使用 ThreadLocal)
}
// 其他方法可以留空或根据需求实现
@Override
public void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {}
@Override
public void clearLocalCache() {}
}
四、InnerInterceptor 的注册
自定义的 InnerInterceptor 需要通过 MyBatis Plus 的配置类注册到插件中。以下是注册示例:
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加自定义 InnerInterceptor
interceptor.addInnerInterceptor(new SqlExecutionTimeInterceptor());
// 也可以添加其他内置拦截器,如分页插件
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
五、常见内置 InnerInterceptor 的使用
1. 分页插件
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
2. 多租户插件
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
@Override
public Expression getTenantId() {
// 返回当前线程的租户 ID(示例)
return new StringValue("tenant_id");
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean ignoreTable(String tableName) {
// 忽略某些表不添加租户条件
return "common_table".equals(tableName);
}
}));
return interceptor;
}
六、注意事项
- 执行顺序:多个
InnerInterceptor的执行顺序与添加顺序一致。 - 性能影响:拦截器会增加 SQL 执行的开销,需合理设计逻辑。
- 兼容性:确保自定义拦截器与 MyBatis Plus 版本兼容。
七、总结
InnerInterceptor 是 MyBatis Plus 提供的一个强大扩展点,允许开发者在 SQL 执行的各个阶段插入自定义逻辑。通过实现 InnerInterceptor 接口并注册到 MyBatis Plus 插件中,可以轻松实现分页、多租户、SQL 日志记录等功能。在实际开发中,建议优先使用内置拦截器,必要时再实现自定义逻辑。

























暂无评论内容