zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    2019计蒜之道初赛第三场题解
    牛客小白月赛14 :部分题目总结
    CF-558:部分题目总结
    浙江省第十六届大学生ACM程序设计竞赛部分题解
    浙江省高职院校联合训练(一)
    CF-544:部分题目总结
    CF-552E-Two Teams
    CF-551:部分题目总结
    freemarker使用map替换字符串中的值
    freemarker使用map替换ftl中相关值
  • 原文地址:https://www.cnblogs.com/jhxxb/p/10644937.html
Copyright © 2011-2022 走看看