MyBatis拦截器

MyBatis拦截器作用

Mybatis可以在执行sql语句的过程中,织入一些拦截器,在不同的节点修改修改一些执行过程中的关键属性,从而影响SQL的生成、执行和返回结果。

MyBatis拦截器提供的扩展点

image

image

拦截执行器方法org.apache.ibatis.executor.Executor

点击查看代码
public interface Executor {

  ResultHandler NO_RESULT_HANDLER = null;

  int update(MappedStatement ms, Object parameter) throws SQLException;

  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;

  List<BatchResult> flushStatements() throws SQLException;

  void commit(boolean required) throws SQLException;

  void rollback(boolean required) throws SQLException;

  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

  boolean isCached(MappedStatement ms, CacheKey key);

  void clearLocalCache();

  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);

  Transaction getTransaction();

  void close(boolean forceRollback);

  boolean isClosed();

  void setExecutorWrapper(Executor executor);

}

拦截SQL语法构建处理org.apache.ibatis.executor.statement.StatementHandler

点击查看代码
public interface StatementHandler {
  // 创建JDBC Statement对象,并完成Statement对象的属性设置
  Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;
  // 使用MyBatis中的ParameterHandler组件为PreparedStatement和CallableStatement参数占位符设置值。
  void parameterize(Statement statement)
      throws SQLException;
  // 将SQL命令添加到批处量执行列表中。
  void batch(Statement statement)
      throws SQLException;
  // 调用Statement对象的execute()方法执行更新语句,例如UPDATE、INSERT、DELETE语句。
  int update(Statement statement)
      throws SQLException;
  // 执行查询语句,并使用ResultSetHandler处理查询结果集。
  <E> List<E> query(Statement statement, ResultHandler resultHandler)
      throws SQLException;
  // 带游标的查询返回Cursor对象。
  <E> Cursor<E> queryCursor(Statement statement)
      throws SQLException;
  // 获取Mapper中配置的SQL信息,BoundSql封装了动态SQL解析后的SQL文本和参数映射信息。
  BoundSql getBoundSql();
  // 获取ParameterHandler实例。
  ParameterHandler getParameterHandler();

}

拦截参数处理org.apache.ibatis.executor.parameter.ParameterHandler

点击查看代码
public interface ParameterHandler {

  Object getParameterObject();

  void setParameters(PreparedStatement ps) throws SQLException;

}

拦截结果集处理org.apache.ibatis.executor.resultset.ResultSetHandler

点击查看代码
public interface ResultSetHandler {

  <E> List<E> handleResultSets(Statement stmt) throws SQLException;

  <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;

  void handleOutputParameters(CallableStatement cs) throws SQLException;

}

各种拦截器的关系图:

image

MyBatis拦截器用法

拦截器提供的注解

@Intercepts
作用:标识当前类为拦截器类
@Signature
作用:
type:就是指定拦截器类型(ParameterHandler ,StatementHandler,ResultSetHandler )
method:是拦截器类型中的方法,不是自己写的方法
args:是method中方法的入参

MyBatis拦截器入门例子

@Slf4j
@Component
@Intercepts(value = {
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class FirstInterceptor implements Interceptor {

    /**
     * 拦截方法逻辑
     * 这里主要是通过反射去获取要执行的SQL相关信息,然后进行操作
     * @param invocation
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        // 代理方法
        log.info("=============== method = " + invocation.getMethod().getName());
        // 代理方法参数
        Object[] args = invocation.getArgs();
        Statement statement = (Statement) args[0];
        // 被代理的对象
        log.info("=============== args = " + invocation.getTarget());
        // 执行目标方法
        Object result = invocation.proceed();
        log.info("=============== result = " + result);
        return result;
    }

    /**
     * 生成MyBatis拦截器代理对象
     * @param target
     * @return
     */
    @Override
    public Object plugin(Object target) {
        if (target instanceof ResultSetHandler) {
            return Plugin.wrap(target, this);
        }

        return target;
    }

    /**
     * 设置插件属性(直接通过Spring的方式获取属性,所以这个方法一般也用不到)
     * 项目启动的时候数据就会被加载
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {

    }
}

结果:

image

posted @ 2023-08-24 23:12  sunpeiyu  阅读(27)  评论(0编辑  收藏  举报