1. 前言

以前是Mybatis XML配套的方式去写,而MybaitsPlus是Mybatis的增强版,抛去了XML文件内容。后者虽然减少了很多繁琐的SQL内容编写,但是同样的,对于复杂的SQL场景,类似流似的SQL生成还是没有XML写法直观。

2. 特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

3. Mybatis层次结构

4. Maven依赖

  com.baomidou            mybatis-plus-boot-starter            3.4.0com.alibaba            druid-spring-boot-starter            1.2.23

5. 插件机制

插件是方便自定义额外功能,比如分页、模糊查询处理特殊字符。我们在编写插件时,除了需要让插件类实现 Interceptor 接口外,还需要通过注解标注 该插件的拦截点。所谓拦截点指的是插件所能拦截的方法,MyBatis 所允许拦截的方法如下:

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

5.1 原理

(1)配置加载插件

com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration:加载任何实现org.apache.ibatis.plugin.Interceptor的自定义插件类。

public MybatisPlusAutoConfiguration(MybatisPlusProperties properties,                                        ObjectProvider interceptorsProvider,                                        ObjectProvider typeHandlersProvider,                                        ObjectProvider languageDriversProvider,                                        ResourceLoader resourceLoader,                                        ObjectProvider databaseIdProvider,                                        ObjectProvider> configurationCustomizersProvider,                                        ObjectProvider> mybatisPlusPropertiesCustomizerProvider,                                        ApplicationContext applicationContext) {        this.properties = properties;        this.interceptors = interceptorsProvider.getIfAvailable();        this.typeHandlers = typeHandlersProvider.getIfAvailable();        this.languageDrivers = languageDriversProvider.getIfAvailable();        this.resourceLoader = resourceLoader;        this.databaseIdProvider = databaseIdProvider.getIfAvailable();        this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();        this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();        this.applicationContext = applicationContext;    }
@Bean@ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {  // ...  if (!ObjectUtils.isEmpty(this.interceptors)) {     factory.setPlugins(this.interceptors);  }  // ...}

(2)Executor

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {    Transaction tx = null;    try {      // ...      // 创建Executor      final Executor executor = configuration.newExecutor(tx, execType);      return new DefaultSqlSession(configuration, executor, autoCommit);    }     catch (Exception e) {...}     finally {...}  }

com.baomidou.mybatisplus.core.MybatisConfiguration#newExecutor

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {        if (useDeprecatedExecutor) {            executorType = executorType == null ? defaultExecutorType : executorType;            executorType = executorType == null ? ExecutorType.SIMPLE : executorType;            Executor executor;            if (ExecutorType.BATCH == executorType) {                executor = new MybatisBatchExecutor(this, transaction);            } else if (ExecutorType.REUSE == executorType) {                executor = new MybatisReuseExecutor(this, transaction);            } else {                executor = new MybatisSimpleExecutor(this, transaction);            }            if (cacheEnabled) {                executor = new MybatisCachingExecutor(executor);            }            // 植入插件            executor = (Executor) interceptorChain.pluginAll(executor);            return executor;        }        return super.newExecutor(transaction, executorType);    }

org.apache.ibatis.plugin.InterceptorChain#pluginAll

public Object pluginAll(Object target) {    // 遍历拦截器    for (Interceptor interceptor : interceptors) {      target = interceptor.plugin(target);    }    return target;  }

案例插件

public Object plugin(Object target) {        return Plugin.wrap(target, this);    }

org.apache.ibatis.plugin.Plugin#wrap

public static Object wrap(Object target, Interceptor interceptor) {    // 获取@Intercepts注解的信息,每一个@Signature注解圈定一个方法    Map, Set> signatureMap = getSignatureMap(interceptor);    Class> type = target.getClass();    // 获取目标类实现的接口    Class>[] interfaces = getAllInterfaces(type, signatureMap);    if (interfaces.length > 0) {      // JDK动态代理,调用invoke方法      return Proxy.newProxyInstance(          type.getClassLoader(),          interfaces,          new Plugin(target, interceptor, signatureMap));    }    return target;  }

org.apache.ibatis.plugin.Plugin#invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    try {      Set methods = signatureMap.get(method.getDeclaringClass());      if (methods != null && methods.contains(method)) {        // 如何方法声明的类包含@Signature声明的方法,则调用拦截器        return interceptor.intercept(new Invocation(target, method, args));      }      return method.invoke(target, args);    } catch (Exception e) {      throw ExceptionUtil.unwrapThrowable(e);    }  }

(3)StatementHandler

com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor#doQuery

public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {        Statement stmt = null;        try {            Configuration configuration = ms.getConfiguration();            // 创建StatementHandler            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);            stmt = prepareStatement(handler, ms.getStatementLog(), false);            return stmt == null ? Collections.emptyList() : handler.query(stmt, resultHandler);        } finally {            closeStatement(stmt);        }    }

org.apache.ibatis.session.Configuration#newStatementHandler

public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);    // 植入插件    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);    return statementHandler;  }

(4)ParameterHandler

org.apache.ibatis.executor.statement.BaseStatementHandler#BaseStatementHandler

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {    // ...    // 创建ParameterHandler    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);    // 创建ResultSetHandler    this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);  }

org.apache.ibatis.session.Configuration#newParameterHandler

public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);    // 植入插件    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);    return parameterHandler;  }

(5)ResultHandler

org.apache.ibatis.session.Configuration#newResultSetHandler

public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,      ResultHandler resultHandler, BoundSql boundSql) {    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);    // 植入插件    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);    return resultSetHandler;  }

4.2 实战

(1)分页插件

   @Bean    public PaginationInnerInterceptor paginationInnerInterceptor() {        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();        paginationInnerInterceptor.setDbType(DbType.MYSQL);        return paginationInnerInterceptor;    }     @Bean    public MybatisPlusInterceptor mybatisPlusInterceptor(ObjectProvider> innerInterceptorProviders) {        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();        List interceptors = innerInterceptorProviders.getIfAvailable();        if (!CollectionUtils.isEmpty(interceptors)) {            for (InnerInterceptor innerInterceptor : interceptors) {                mybatisPlusInterceptor.addInnerInterceptor(innerInterceptor);            }        }        return mybatisPlusInterceptor;    }

(2)模糊查询处理特殊字符

         @Bean    public FuzzyQueryInterceptor fuzzyQueryInterceptor() {        return new FuzzyQueryInterceptor();    }
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import org.apache.ibatis.cache.CacheKey;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.plugin.*;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import priv.whh.std.boot.mybatis.plus.util.EscapeUtil; import java.lang.reflect.InvocationTargetException;import java.util.HashMap;import java.util.HashSet;import java.util.Properties;import java.util.Set; /** * 模糊查询拦截器方法,处理模糊查询中包含特殊字符(_、%、) * */@Intercepts({        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,                RowBounds.class, ResultHandler.class}),        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,                RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})})public class FuzzyQueryInterceptor implements Interceptor {    private static final String LIKE = " like ";    private static final String QUESTION_MARK = "?";    private static final String LIKE_WITH_QUESTION_MARK = " like ?";    private static final String UNDERLINE = "_";    private static final String PERCENT = "%";    private static final String EW = "ew";    private static final String EW_PARAM_NAME_VALUE_PAIRS = "ew.paramNameValuePairs.";    private static final String DOUBLE_SLASH = "";    private static final String DOUBLE_SLASH_WITH_SPOT = ".";    private static final String DOUBLE_SLASH_WITH_QUESTION_MARK = "?";     @Override    public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {        // 拦截sql        Object[] args = invocation.getArgs();        MappedStatement statement = (MappedStatement) args[0];        Object parameterObject = args[1];        BoundSql boundSql = statement.getBoundSql(parameterObject);        String sql = boundSql.getSql();        // 处理特殊字符        Object param = modifyLikeSql(sql, parameterObject, boundSql);        args[1] = param;        // 返回        return invocation.proceed();    }     @Override    public Object plugin(Object target) {        return Plugin.wrap(target, this);    }     @Override    public void setProperties(Properties properties) {     }     @SuppressWarnings("unchecked")    public static Object modifyLikeSql(String sql, Object parameterObject, BoundSql boundSql) {        boolean paramJudge = parameterObject instanceof HashMap || parameterObject instanceof String;        if (!paramJudge) {            return parameterObject;        }        if (!sql.toLowerCase().contains(LIKE) || !sql.toLowerCase().contains(QUESTION_MARK)) {            return parameterObject;        }        // 获取关键字的个数(去重)        String[] strList = sql.split(DOUBLE_SLASH_WITH_QUESTION_MARK);        Set keyNames = new HashSet<>();        for (int i = 0; i < strList.length; i++) {            if (strList[i].toLowerCase().contains(LIKE)) {                String keyName = boundSql.getParameterMappings().get(i).getProperty();                keyNames.add(keyName);            }        }        // 对关键字进行特殊字符“清洗”,如果有特殊字符的,在特殊字符前添加转义字符()        for (String keyName : keyNames) {            HashMap parameter;            if (parameterObject instanceof HashMap) {                parameter = (HashMap) parameterObject;            } else {                parameter = new HashMap<>(2);                parameter.put(keyName, parameterObject);            }            if (keyName.contains(EW_PARAM_NAME_VALUE_PAIRS) && sql.toLowerCase().contains(LIKE_WITH_QUESTION_MARK)) {                // 第一种情况:在业务层进行条件构造产生的模糊查询关键字                QueryWrapper wrapper = (QueryWrapper) parameter.get(EW);                parameter = (HashMap) wrapper.getParamNameValuePairs();                 String[] keyList = keyName.split(DOUBLE_SLASH_WITH_SPOT);                // ew.paramNameValuePairs.MPGENVAL1,截取字符串之后,获取第三个,即为参数名                Object a = parameter.get(keyList[2]);                boolean judge = a instanceof String && (a.toString().contains(UNDERLINE)                        || a.toString().contains(DOUBLE_SLASH) || a.toString().contains(PERCENT));                if (judge) {                    parameter.put(keyList[2],                            PERCENT + EscapeUtil.escapeChar(a.toString().substring(1, a.toString().length() - 1)) + PERCENT);                }            } else if (!keyName.contains(EW_PARAM_NAME_VALUE_PAIRS) && sql.toLowerCase().contains(LIKE_WITH_QUESTION_MARK)) {                // 第二种情况:未使用条件构造器,但是在service层进行了查询关键字与模糊查询符`%`手动拼接                Object a = parameter.get(keyName);                boolean judge = a instanceof String && (a.toString().contains(UNDERLINE)                        || a.toString().contains(DOUBLE_SLASH) || a.toString().contains(PERCENT));                if (judge) {                    parameter.put(keyName,                            PERCENT + EscapeUtil.escapeChar(a.toString().substring(1, a.toString().length() - 1)) + PERCENT);                }            } else {                // 第三种情况:在Mapper类的注解SQL或者XML中进行了模糊查询的拼接                Object a = parameter.get(keyName);                boolean judge = a instanceof String && (a.toString().contains(UNDERLINE)                        || a.toString().contains(DOUBLE_SLASH) || a.toString().contains(PERCENT));                if (judge) {                    parameter.put(keyName, EscapeUtil.escapeChar(a.toString()));                    if (parameterObject instanceof String) {                        parameterObject = EscapeUtil.escapeChar(a.toString());                    }                }            }        }        return parameterObject;    }}

6. 缓存机制

7. 会话机制

9. 配置

10. FAQ

Q:Mybatis如何做到防SQL注入?

A: Mybatis 使用 #{?} 时,会进行sql的预编译(select * from t_user where a = ?);使用${?}时,不会进行sql的预编译(select * from t_user where a = 1),这样的话,会有sql注入的风险。经测试,sql注入无法注入两条sql语句,会报错。只能注入类似(select * from t_user where a = 1 or 1 = 1), 注入的变量为 “‘1’ or 1 = 1”;

Q:除了配置的方式,QueryWrap可以通过打断点的方式查看组装的SQL吗?

A:不能

Q:数据库时间戳接收用Date还是LocalDateTime接收好?

Q:在继承BaseMapper文件中, MybatisPlus是否支持任意自定义对象返回,如返回Person?

Q:Mybatis-plus selectOne函数如何限制返回一条数据?

11. 结尾

本文到这里就结束了,感谢看到最后的朋友,都看到最后了,点个赞再走啊,如有不对之处还请多多指正。

mybatisplus查询今天的数据_Spring系列——MybatisPlus相关推荐

  1. mybatisplus查询今天的数据_springboot集成mybatisPlus

    一 前言 mybatisPlus 能够简化开发,减少重复代码,很不错的一个项目!! 二 springboot 集成 mybatisPlus 2.1准备工作 建表语句 CREATE 项目依赖 <d ...

  2. mybatisplus查询今天的数据_MybatisPlus(CRUD)

    插入功能 //测试插入@Testpublic void testInsert(){ User user = new User(); user.setName("ironman"); ...

  3. mybatis-plus 查询,删除

    title 查询 单值,多个主键,条件 分页查询 物理删除,逻辑删除 mybatis-plus 新增,修改 查询 单值,多个主键,条件 @Testvoid queryOne() {// 查询单个use ...

  4. Mybatis-plus 查询指定字段 select

    Mybatis-plus 查询指定字段 select 表结构 CREATE TABLE `user` (`id` bigint(20) NOT NULL COMMENT '主键',`name` var ...

  5. MyBatisPlus查询时报错,Unknow column ‘id‘ in ‘field list‘,怎么解决?

    在使用MyBatisPlus的selectById()方法查询数据时,报出了一个错误: java.sql.SQLSyntaxErrorException Create breakpoint Unkno ...

  6. mybatis-plus 分页后没有数据问题(超过当前数据量的页)

    mybatis-plus 分页后没有数据问题(超过当前数据量的页) 问题 代码如下 解决 问题 我查询接口(当前数据表里有10条记录 我设置page为2页,当前一页大小为10) 然后查询,返回结果为空 ...

  7. MybatisPlus查询条件和排序高级封装

    1.查询注解 import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java. ...

  8. Mybatis-Plus查询之条件查询(用户名查询)(批量查询)

    Mybatis-Plus查询之条件查询(用户名查询)(批量查询) 上代码 上代码 //查询多个用户//Arrays.asList 工具类List<User> users = iUserRe ...

  9. 大数据算法系列——布隆过滤器

    大数据算法系列--布隆过滤器 一.简介 Bloom filter介绍 Bloom Filter(BF)是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集 ...

最新文章

  1. 未来50年的神经科学会是什么样呢?
  2. php cdi_本机CDI限定词:@Any和@Default
  3. jvm7 jvm8_自我修复的JVM
  4. 5888. 网络空闲的时刻
  5. 三星Galaxy Note20系列价格曝光:大小杯差距明显
  6. java 查找排序_数据结构(Java)——查找和排序(1)
  7. java二进制命令_Java二进制指令代码解析
  8. 秀恩爱分得快-模拟题
  9. 五句话介绍计算机英语,用英语描写电脑优点(5个句子)和缺点(5个句子),一共10句话哦....
  10. LAMMPS学习总结1
  11. usb转rs485 linux驱动下载,USB转RS485串口驱动
  12. SpringBoot整合mybatis一直失败差不到数据,解决方案
  13. 网站建设费用贵和便宜有什么区别?
  14. python软件要钱吗-python语言是免费还是收费的?
  15. Python三步爬取VMgirls小姐姐图片
  16. 软件测试Selenium-API 操作(上机练习文档)分享
  17. g++/gcc compile_options
  18. Flutter (四) 基础 Widgets、Material Components Widget 全面介绍
  19. Jieba库实现词性标注及小说人物角色抽取
  20. 浅谈百度阅读/文库NA端排版技术

热门文章

  1. ansj 自定义 停用词_构造自定义停用词列表的快速提示
  2. 递归函数非递归化_递归神秘化
  3. python seaborn heatmap可视化相关性矩阵
  4. 阿里大鱼php发送短信,阿里大鱼短信发送PHP代码
  5. vscode用作markdown入门2--代码上下标目录字体
  6. 使用OpenExif修改jpeg图片信息
  7. 用Python标准库turtle画一头金牛,祝您新年牛气冲天!
  8. 【CCF】201903-1小中大
  9. C#开发ActiveX控件及制作CAB包
  10. NLP《词汇表示方法(三)word2vec》