MyBatis-Plugins

MyBatis 允许在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

除了用插件来修改 MyBatis 核心行为之外,还可以通过完全覆盖配置类来达到目的。只需继承后覆盖其中的每个方法,再把它传递到 SqlSessionFactoryBuilder.build(myConfig) 方法即可。

一、可拦截的接口

1.Executor-执行器

public interface Executor {
    // 不需要 ResultHandler
    ResultHandler NO_RESULT_HANDLER = null;
    // 更新
    int update(MappedStatement ms, Object parameter) throws SQLException;
    // 查询(先查缓存),带分页,BoundSql
    <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;
    // 刷新(Statement)批处理语句
    List<BatchResult> flushStatements() throws SQLException;
    // 提交事务,参数为是否要强制
    void commit(boolean required) throws SQLException;
    // 回滚事务,参数为是否要强制
    void rollback(boolean required) throws SQLException;
    // 创建 CacheKey
    CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);
    // 判断是否缓存了,通过 CacheKey
    boolean isCached(MappedStatement ms, CacheKey key);
    // 清理 Session(本地一级) 缓存
    void clearLocalCache();
    // 延迟加载
    void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);
    // 获取事务
    Transaction getTransaction();
    // 关闭连接
    void close(boolean forceRollback);
    // 是否关闭
    boolean isClosed();
    // 设置 Executor
    void setExecutorWrapper(Executor executor);
}

2.ParameterHandler-参数处理器

public interface ParameterHandler {
    // 获取参数
    Object getParameterObject();
    // 设置参数
    void setParameters(PreparedStatement ps) throws SQLException;
}

3.ResultSetHandler-结果集处理器

public interface ResultSetHandler {
    // 将结果集转化成 List
    <E> List<E> handleResultSets(Statement stmt) throws SQLException;
    // 将结果集转化成 Cursor
    <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
    // 处理存储过程的 OUT(输出) 参数
    void handleOutputParameters(CallableStatement cs) throws SQLException;
}

4.StatementHandler-SQL语句处理器

public interface StatementHandler {
    // 准备语句
    Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
    // 参数处理
    void parameterize(Statement statement) throws SQLException;
    // 批量处理
    void batch(Statement statement) throws SQLException;
    // 更新处理
    int update(Statement statement) throws SQLException;
    // 查询处理,结果给 ResultHandler
    <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
    <E> Cursor<E> queryCursor(Statement statement) throws SQLException;
    // 获取绑定 SQL 语句
    BoundSql getBoundSql();
    // 获取参数处理器
    ParameterHandler getParameterHandler();
}

二、自定义插件

实现 Interceptor 接口,并指定想要拦截的方法签名。最后在 xml 文件中配置全类名即可。

1.bean

@Alias("myUser")
public class MyUser implements Serializable {
    private Integer id;
    private String name;
    private Integer age;

2.dao接口

public interface MyUserMapperAnnotation {
    @Select("select * from myuser")
    List<MyUser> selectMyUser(String a);
}

3.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 在配置文件中的位置
        properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers? -->
    <plugins>
        <plugin interceptor="com.plugins.ExamplePlugin">
            <property name="someProperty" value="100"/>
        </plugin>
    </plugins>

    <environments default="development-mysql">
        <environment id="development-mysql">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.8.136:3306/mybatis?allowMultiQueries=true"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper class="com.dao.MyUserMapperAnnotation"/>
    </mappers>
</configuration>

4.ExamplePlugin

/**
 * @Intercepts 拦截器注解,包括一个或多个 @Signature
 * @Signature 拦截的目标类信息,包括 type、method、args
 * * type 要拦截的接口类型
 * * method 接口中的方法名
 * * args 方法的所有入参类型
 */
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class ExamplePlugin implements Interceptor {
    /**
     * 拦截目标对象的目标方法的执行,将自定义逻辑写在该方法中
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("ExamplePlugin...intercept:" + invocation.getMethod());

        // MetaObject 是 Mybatis 提供的一个用于访问对象属性的对象
        MetaObject metaObject = SystemMetaObject.forObject(invocation);

        System.out.println("当前拦截到的对象:" + metaObject.getValue("target"));
        System.out.println("SQL语句:" + metaObject.getValue("target.delegate.boundSql.sql"));
        System.out.println("SQL语句入参:" + metaObject.getValue("target.delegate.parameterHandler.parameterObject"));
        System.out.println("SQL语句类型:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.sqlCommandType"));
        System.out.println("Mapper方法全路径名:" + metaObject.getValue("target.delegate.parameterHandler.mappedStatement.id"));

        // 修改 SQL 语句
        String newSQL = metaObject.getValue("target.delegate.boundSql.sql") + " limit 2";
        metaObject.setValue("target.delegate.boundSql.sql", newSQL);
        System.out.println("修改后SQL语句:" + newSQL);

        // 返回执行结果
        return invocation.proceed();
    }

    /**
     * 为目标对象创建一个代理对象,使用 Plugin.wrap(target,this) 即可
     * @param target 上次包装的代理对象
     * @return 本次包装过的代理对象
     */
    @Override
    public Object plugin(Object target) {
        System.out.println("ExamplePlugin...plugin:" + target);
        return Plugin.wrap(target, this);
    }

    /**
     * 获取自定义配置参数
     * @param properties
     */
    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置信息:" + properties);
        System.out.println("someProperty:" + properties.get("someProperty"));
    }
}

5.Main

public static void main(String[] args) throws IOException {
    SqlSession session = null;
    try {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        session = sqlSessionFactory.openSession();
        MyUserMapperAnnotation mapper = session.getMapper(MyUserMapperAnnotation.class);

        System.out.println(mapper.selectMyUser("asdsad"));
    } finally {
        if (session != null) {
            session.close();
        }
    }
}


http://www.mybatis.org/mybatis-3/zh/configuration.html#plugins

原文地址:https://www.cnblogs.com/jhxxb/p/10644937.html