mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比,于是写了个插件。 (2)

简介: mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比,于是写了个插件。 (2)

mybatis 插件开发


基于上面这三步,大家先看一下我们这插件怎么写,以及这个插件的效果。


先说明一下本文涉及到的源码 mybatis 版本是 3.4.0。


本文用拦截器的目的是判断 delete 语句中是否有 where 条件。所以,开发出来的插件长这样:


再来一个复制粘贴直接运行版本:


@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update",
                args = {MappedStatement.class, Object.class}),
})
public class CheckSQLInterceptor implements Interceptor {
    private static String SQL_WHERE = "where";
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取方法的第0个参数,也就是MappedStatement。@Signature注解中的args中的顺序
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        //获取sql命令操作类型
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        final Object[] queryArgs = invocation.getArgs();
        final Object parameter = queryArgs[1];
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        String sql = boundSql.getSql();
        if (SqlCommandType.DELETE.equals(sqlCommandType)) {
            //格式化sql
            sql = sql.replace("\n", "");
            if (!sql.toLowerCase().contains(SQL_WHERE)) {
                sql = sql.replace(" ", "");
                log.info("删除语句中没有where条件,sql为:{}", sql);
                throw new Exception("删除语句中没有where条件");
            }
        }
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }
    @Override
    public void setProperties(Properties properties) {
    }
}


再把插件注册上(注册插件还有其他的方法,后面会讲到,这里只是展示Bean注入的方式):


我们先看看配上插件后的执行效果:


可以看到日志中输出了:


删除语句中没有where条件,sql为:delete from order_info_ext

并抛出了异常。


这样,我们的扩展表的数据就保住了。在测试阶段,测试同学就一定能扯出来问题,瞟一眼日志就明白了。


就算测试同学忘记测试了,在生产上也不会执行成功,抛出异常后还会有报警短信通知到相应的开发负责人,及时登上服务器去处理。


功能实现了,确实是非常的简单。


我们再说回代码,你说说看:当你拿到上面这段代码后,最迷惑的地方是哪里?


其中的逻辑是很简单的了。 没有什么特别的地方,我想大多数人拿到这段代码迷惑的地方在于这个地方吧:


这个 @Intercepts 里面的 @Signature 里面为什么要这样配置?

我们先看看 @Intercepts 注解:


里面是个数组,可以配置多个 Signature。所以,其实这样配置也是可以的:


关键的地方在于 @Signature 怎么配置:


这个问题,我们放到下一节去讨论。


mybatis插件的原理


上面一小节我们知道了对于开发插件而言,难点在于 @Signature 怎么配置。


其实这也不能叫难点,只能说你不知道能配置什么,比较茫然而已。这一小节就来回答这个问题。


要知道怎么配置就必须要了解mybatis 这四大对象:Executor、ParameterHandler 、ResultSetHandler 、StatementHandler 。


官网上说:


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


Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)


ParameterHandler (getParameterObject, setParameters)


ResultSetHandler (handleResultSets, handleOutputParameters)


StatementHandler (prepare, parameterize, batch, update, query)


那官网上说的这四大对象分别是拿来干啥用的呢?


Executor:Mybatis 的执行器,用于进行增删改查的操作。


ParameterHandler :参数处理器,用于处理 SQL 语句中的参数对象。


ResultSetHandler:结果处理器,用于处理 SQL 语句的返回结果。


StatementHandler :数据库的处理对象,用于执行SQL语句


知道拦截的四大对象了,我们就可以先揭秘一下上面的这个注解配置的是啥了:


type 字段存放的是 class 对象,其取值范围就是上面说的四大对象。


method 字段存放的是 class 对象的具体方法。


args 存放的是具体方法的参数。


看到这几个参数你想到了什么?有没有条件反射式的想到反射?如果没有的话你再咂摸咂摸,看看能不能品出一点反射的味道。


本文用拦截器的目的是判断 delete 语句中是否有 where 条件,因此经过上面的分析,Executor 对象就能满足我们的需求。


所以在本文示例中 @Signature 的 type 字段就是 Executor.class。


那 method 字段我们放哪个方法呢?放 delete 吗?


这就得看看 Executor 对象的方法有哪些:


可以看到其中并没有 delete 方法,和 SQL 执行相关的,看起来只有 query和 update。

但是,我们可以大胆猜测一下呀:delete 也是一种 update。


接着去求证一下就行:


可以看到 delete 方法确实是调用了 update 方法。


所以在本文案例中 @Signature 的 method 字段放的是 update 方法。


已经知道具体的方法了,那 args 放的就是方法的入参,所以这段配置就是这样来的:


真的,我觉得这属于手摸手教学系列了。经过这个简单的案例,我希望大家能做到一通百通。


接下来带大家看看我们常用的分页插件 pageHelper 是怎么做的吧。


其实你用脚指头也能想到,分页插件肯定是拦截的查询方法,我们只是需要去验证一下就可以。


引入 pageHelper 后可以看到 Interceptor 的多了两个实现:


我们看一下 PageInterceptor 方法吧:


对吧,拦截了两个 query 方法,一个参数是 4 个,一个参数是 6 个:


同时,在 intercept 的实现里面有一部分是这样写的:


4 个参数和 6 个参数是做了单独处理的,至于为什么要这样处理,至于为什么要拦截两个 query 方法,说起来又是一个很长的故事了。


详细的可以看看这个链接: https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md


好了,还是那句话:如果要写出好的 mybatis 插件,必须知道 @Signature 怎么去配置。配置后能拦截哪些东西,你心里应该是有点数的。

目录
相关文章
|
1月前
|
XML Java 数据库连接
mybatis-plus逆向工程详解
mybatis-plus逆向工程详解
|
2月前
|
Java 数据库连接 Maven
使用mybatis插件generator生成实体类,dao层和mapper映射
使用mybatis插件generator生成实体类,dao层和mapper映射
50 0
|
17天前
|
SQL Java 数据库连接
【mybatis】第一篇,Springboot中使用插件PageHelper不生效解决方案
【mybatis】第一篇,Springboot中使用插件PageHelper不生效解决方案
|
1天前
|
SQL XML Java
Mybatis-Plus插件扩展MybatisX
Mybatis-Plus插件扩展MybatisX
11 0
|
2月前
|
XML 监控 druid
【Java专题_02】springboot+mybatis+pagehelper分页插件+druid数据源详细教程
【Java专题_02】springboot+mybatis+pagehelper分页插件+druid数据源详细教程
|
3月前
|
Java 数据库连接 数据库
【MyBatis】tkMapper 插件
【1月更文挑战第14天】【MyBatis】tkMapper 插件
|
3月前
|
Java 数据库连接 Maven
MyBatis逆向工程可以生成哪些内容?
MyBatis逆向工程可以生成哪些内容?
18 0
|
3月前
|
Java 数据库连接 mybatis
Mybatis之分页插件
【1月更文挑战第5天】 一、分页插件使用步骤 1、添加依赖 2、配置分页插件 二、分页插件的使用 1、开启分页功能 2、分页相关数据 方法一:直接输出 方法二使用PageInfo 常用数据:
50 1
|
1月前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
42 1
|
1月前
|
druid Java 数据库连接
Spring Boot3整合MyBatis Plus
Spring Boot3整合MyBatis Plus
45 1