Mybatis-Plus使用全解

前言

之前写了《SpringBoot | 第九章:Mybatis-plus 的集成和使用》一文,只是简单的使用条件构造器列举了一些通用的 CURD 操作。本人也想写一篇通用的关于mybatis-plus的使用示例,一方面也让自己更加了解mybatismybatis-plus,另一方面,也因为很多新人刚入职公司时,对这块不是很熟悉,会有一些疑惑。所以,总的来说还是作为一份资产,可供人查阅,这样也能减少了很多的沟通成本。


所以本章节,就主要来讲解下关于Mybatis-plus的不同场景的用法,目前主要想到的是以下几个知识点,也是很常用的知识点了,后面有补充的会再启章节来记录的。另外,官网的文档已经很详尽了,大家可认真查阅下。

  1. 代码生成器
  2. 通用的 CURD
  3. 条件构造器
  4. 自定义 SQL 语句
  5. 分页插件、性能分析插件
  6. 公共字段自动填充

工程准备

这里还是以user表为例子,数据库为 mysql

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(20) DEFAULT NULL COMMENT '唯一标示',
  `code` varchar(20) DEFAULT NULL COMMENT '编码',
  `name` varchar(64) DEFAULT NULL COMMENT '名称',
  `status` char(1) DEFAULT '1' COMMENT '状态 1 启用 0 停用',
  `gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

关于SpringBootMybatis-plus的集成,这里就不阐述了,这个不是今天的重点。不熟悉的同学,可移步:http://blog.lqdev.cn/2018/07/21/springboot/chapter-nine/进行查看了解。

代码生成器

Mybatis-Plus已经提供了大量的自定义设置,生成的代码完全能够满足各类型的需求,基本覆盖了大部分的配置了。这里贴一个比较完整的代码生成器类,大家可根据实际情况进行修改。

MysqlGenerator.java:

// 省略了 import
public class MysqlGenerator {
<span class="hljs-comment">/**
 * 包名
 */</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">PACKAGE_NAME</span> <span class="hljs-operator">=</span> <span class="hljs-string">"cn.lqdev.learning.mybatisplus.samples"</span>;
<span class="hljs-comment">/**
 * 模块名称
 */</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">MODULE_NAME</span> <span class="hljs-operator">=</span> <span class="hljs-string">"biz"</span>;
<span class="hljs-comment">/**
 * 输出文件的路径
 */</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">OUT_PATH</span> <span class="hljs-operator">=</span> <span class="hljs-string">"D:\\develop\\code"</span>;
<span class="hljs-comment">/**
 * 代码生成者
 */</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">AUTHOR</span> <span class="hljs-operator">=</span> <span class="hljs-string">"oKong"</span>;

<span class="hljs-comment">/**
 * JDBC相关配置
 */</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">DRIVER</span> <span class="hljs-operator">=</span> <span class="hljs-string">"com.mysql.jdbc.Driver"</span>;
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">URL</span> <span class="hljs-operator">=</span> <span class="hljs-string">"jdbc:mysql://127.0.0.1:3306/learning?useUnicode=true&amp;characterEncoding=UTF-8"</span>;
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">USER_NAME</span> <span class="hljs-operator">=</span> <span class="hljs-string">"root"</span>;
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">PASSWORD</span> <span class="hljs-operator">=</span> <span class="hljs-string">"bs"</span>;

<span class="hljs-comment">/**
 * &lt;p&gt;
 * MySQL 生成演示
 * &lt;/p&gt;
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> {
    <span class="hljs-comment">// 自定义需要填充的字段</span>
    List&lt;TableFill&gt; tableFillList = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;TableFill&gt;();
    <span class="hljs-comment">//如 每张表都有一个创建时间、修改时间</span>
    <span class="hljs-comment">//而且这基本上就是通用的了,新增时,创建时间和修改时间同时修改</span>
    <span class="hljs-comment">//修改时,修改时间会修改,</span>
    <span class="hljs-comment">//虽然像Mysql数据库有自动更新几只,但像ORACLE的数据库就没有了,</span>
    <span class="hljs-comment">//使用公共字段填充功能,就可以实现,自动按场景更新了。</span>
    <span class="hljs-comment">//如下是配置</span>
    <span class="hljs-type">TableFill</span> <span class="hljs-variable">createField</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TableFill</span>(<span class="hljs-string">"gmt_create"</span>, FieldFill.INSERT); 
    <span class="hljs-type">TableFill</span> <span class="hljs-variable">modifiedField</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">TableFill</span>(<span class="hljs-string">"gmt_modified"</span>, FieldFill.INSERT_UPDATE); 
    tableFillList.add(createField);
    tableFillList.add(modifiedField);
    
    <span class="hljs-comment">// 代码生成器</span>
    <span class="hljs-type">AutoGenerator</span> <span class="hljs-variable">mpg</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AutoGenerator</span>().setGlobalConfig(
            <span class="hljs-comment">// 全局配置</span>
            <span class="hljs-keyword">new</span> <span class="hljs-title class_">GlobalConfig</span>().setOutputDir(OUT_PATH)<span class="hljs-comment">// 输出目录</span>
                    .setFileOverride(<span class="hljs-literal">true</span>)<span class="hljs-comment">// 是否覆盖文件</span>
                    .setActiveRecord(<span class="hljs-literal">true</span>)<span class="hljs-comment">// 开启 activeRecord 模式</span>
                    .setEnableCache(<span class="hljs-literal">false</span>)<span class="hljs-comment">// XML 二级缓存</span>
                    .setBaseResultMap(<span class="hljs-literal">false</span>)<span class="hljs-comment">// XML ResultMap</span>
                    .setBaseColumnList(<span class="hljs-literal">true</span>)<span class="hljs-comment">// XML columList</span>
                    .setAuthor(AUTHOR)
                    <span class="hljs-comment">// 自定义文件命名,注意 %s 会自动填充表实体属性!</span>
                    .setXmlName(<span class="hljs-string">"%sMapper"</span>).setMapperName(<span class="hljs-string">"%sDao"</span>)
    <span class="hljs-comment">// .setServiceName("MP%sService")</span>
    <span class="hljs-comment">// .setServiceImplName("%sServiceDiy")</span>
    <span class="hljs-comment">// .setControllerName("%sAction")</span>
    ).setDataSource(
            <span class="hljs-comment">// 数据源配置</span>
            <span class="hljs-keyword">new</span> <span class="hljs-title class_">DataSourceConfig</span>().setDbType(DbType.MYSQL)<span class="hljs-comment">// 数据库类型</span>
                    .setTypeConvert(<span class="hljs-keyword">new</span> <span class="hljs-title class_">MySqlTypeConvert</span>() {
                        <span class="hljs-comment">// 自定义数据库表字段类型转换【可选】</span>
                        <span class="hljs-meta">@Override</span>
                        <span class="hljs-keyword">public</span> DbColumnType <span class="hljs-title function_">processTypeConvert</span><span class="hljs-params">(String fieldType)</span> {
                            System.out.println(<span class="hljs-string">"转换类型:"</span> + fieldType);
                            <span class="hljs-comment">// if ( fieldType.toLowerCase().contains( "tinyint" ) ) {</span>
                            <span class="hljs-comment">// return DbColumnType.BOOLEAN;</span>
                            <span class="hljs-comment">// }</span>
                            <span class="hljs-keyword">return</span> <span class="hljs-built_in">super</span>.processTypeConvert(fieldType);
                        }
                    }).setDriverName(DRIVER).setUsername(USER_NAME).setPassword(PASSWORD).setUrl(URL))
            .setStrategy(
                    <span class="hljs-comment">// 策略配置</span>
                    <span class="hljs-keyword">new</span> <span class="hljs-title class_">StrategyConfig</span>()
                            <span class="hljs-comment">// .setCapitalMode(true)// 全局大写命名</span>
                            .setDbColumnUnderline(<span class="hljs-literal">true</span>)<span class="hljs-comment">// 全局下划线命名</span>
                            <span class="hljs-comment">// .setTablePrefix(new String[]{"unionpay_"})// 此处可以修改为您的表前缀</span>
                            .setNaming(NamingStrategy.underline_to_camel)<span class="hljs-comment">// 表名生成策略</span>
                            <span class="hljs-comment">// .setInclude(new String[] {"user"}) // 需要生成的表</span>
                            <span class="hljs-comment">// .setExclude(new String[]{"test"}) // 排除生成的表</span>
                            <span class="hljs-comment">// 自定义实体,公共字段</span>
                            <span class="hljs-comment">// .setSuperEntityColumns(new String[]{"test_id"})</span>
                            .setTableFillList(tableFillList)
                            <span class="hljs-comment">// 自定义实体父类</span>
                            <span class="hljs-comment">// .setSuperEntityClass("com.baomidou.demo.base.BsBaseEntity")</span>
                            <span class="hljs-comment">// // 自定义 mapper 父类</span>
                            <span class="hljs-comment">// .setSuperMapperClass("com.baomidou.demo.base.BsBaseMapper")</span>
                            <span class="hljs-comment">// // 自定义 service 父类</span>
                            <span class="hljs-comment">// .setSuperServiceClass("com.baomidou.demo.base.BsBaseService")</span>
                            <span class="hljs-comment">// // 自定义 service 实现类父类</span>
                            <span class="hljs-comment">// .setSuperServiceImplClass("com.baomidou.demo.base.BsBaseServiceImpl")</span>
                            <span class="hljs-comment">// 自定义 controller 父类</span>
                            <span class="hljs-comment">// .setSuperControllerClass("com.baomidou.demo.TestController")</span>
                            <span class="hljs-comment">// 【实体】是否生成字段常量(默认 false)</span>
                            <span class="hljs-comment">// public static final String ID = "test_id";</span>
                            .setEntityColumnConstant(<span class="hljs-literal">true</span>)
                            <span class="hljs-comment">// 【实体】是否为构建者模型(默认 false)</span>
                            <span class="hljs-comment">// public User setName(String name) {this.name = name; return this;}</span>
                            .setEntityBuilderModel(<span class="hljs-literal">true</span>)
                            <span class="hljs-comment">// 【实体】是否为lombok模型(默认 false)&lt;a href="https://projectlombok.org/"&gt;document&lt;/a&gt;</span>
                            .setEntityLombokModel(<span class="hljs-literal">true</span>)
            <span class="hljs-comment">// Boolean类型字段是否移除is前缀处理</span>
            <span class="hljs-comment">// .setEntityBooleanColumnRemoveIsPrefix(true)</span>
            <span class="hljs-comment">// .setRestControllerStyle(true)</span>
            <span class="hljs-comment">// .setControllerMappingHyphenStyle(true)</span>
            ).setPackageInfo(
                    <span class="hljs-comment">// 包配置</span>
                    <span class="hljs-keyword">new</span> <span class="hljs-title class_">PackageConfig</span>().setModuleName(MODULE_NAME).setParent(PACKAGE_NAME)<span class="hljs-comment">// 自定义包路径</span>
                            .setController(<span class="hljs-string">"controller"</span>)<span class="hljs-comment">// 这里是控制器包名,默认 web</span>
                            .setXml(<span class="hljs-string">"mapper"</span>).setMapper(<span class="hljs-string">"dao"</span>)

            ).setCfg(
                    <span class="hljs-comment">// 注入自定义配置,可以在 VM 中使用 cfg.abc 设置的值</span>
                    <span class="hljs-keyword">new</span> <span class="hljs-title class_">InjectionConfig</span>() {
                        <span class="hljs-meta">@Override</span>
                        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">initMap</span><span class="hljs-params">()</span> {
                            Map&lt;String, Object&gt; map = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;String, Object&gt;();
                            map.put(<span class="hljs-string">"abc"</span>, <span class="hljs-built_in">this</span>.getConfig().getGlobalConfig().getAuthor() + <span class="hljs-string">"-mp"</span>);
                            <span class="hljs-built_in">this</span>.setMap(map);
                        }
                    }.setFileOutConfigList(
                            Collections.&lt;FileOutConfig&gt;singletonList(<span class="hljs-keyword">new</span> <span class="hljs-title class_">FileOutConfig</span>(<span class="hljs-string">"/templates/mapper.xml.vm"</span>) {
                                <span class="hljs-comment">// 自定义输出文件目录</span>
                                <span class="hljs-meta">@Override</span>
                                <span class="hljs-keyword">public</span> String <span class="hljs-title function_">outputFile</span><span class="hljs-params">(TableInfo tableInfo)</span> {
                                    <span class="hljs-keyword">return</span> OUT_PATH + <span class="hljs-string">"/xml/"</span> + tableInfo.getEntityName() + <span class="hljs-string">"Mapper.xml"</span>;
                                }
                            })))
            .setTemplate(
                    <span class="hljs-comment">// 关闭默认 xml 生成,调整生成 至 根目录</span>
                    <span class="hljs-keyword">new</span> <span class="hljs-title class_">TemplateConfig</span>().setXml(<span class="hljs-literal">null</span>)
    <span class="hljs-comment">// 自定义模板配置,模板可以参考源码 /mybatis-plus/src/main/resources/template 使用 copy</span>
    <span class="hljs-comment">// 至您项目 src/main/resources/template 目录下,模板名称也可自定义如下配置:</span>
    <span class="hljs-comment">// .setController("...");</span>
    <span class="hljs-comment">// .setEntity("...");</span>
    <span class="hljs-comment">// .setMapper("...");</span>
    <span class="hljs-comment">// .setXml("...");</span>
    <span class="hljs-comment">// .setService("...");</span>
    <span class="hljs-comment">// .setServiceImpl("...");</span>
    );

    <span class="hljs-comment">// 执行生成</span>
    mpg.execute();
}

}

按以上代码生成器,生成的目录结构如下(依赖中需要加入velocity-engine-core包,是利用模版引擎来生成的)

工程结构

对应 mapper.xml

对于需要自定义模版时,大家可查看官方的mybatis-plus-generate包,默认的官方模版都放在此包下。

官方模版

有了代码生成器,省了很多机械性的复制黏贴操作,还不会出错,写错了再执行一次就好了!

通用的 CURD

MP提供了ActiveRecord的支持,所以实体类只需继承 Model 类即可实现基本 CRUD 操作。

这里以编写测试类的形式,进行通用 CURD 操作,代码类有相应的注释说明。

GeneralTest.java:

/**
 * 通用 CURD 示例
 * @author oKong
 *
 */
@RunWith(SpringRunner.class)
//SpringBootTest 是 springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。
@SpringBootTest 
@Slf4j
public class GeneralTest {
<span class="hljs-meta">@Autowired</span>
IUserService userService;

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testInsert</span><span class="hljs-params">()</span> {
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"001"</span>);
    user.setName(<span class="hljs-string">"okong-insert"</span>);
    <span class="hljs-comment">//默认的插入策略为:FieldStrategy.NOT_NULL,即:判断 null</span>
    <span class="hljs-comment">//对应在mapper.xml时写法为:&lt;if test="field!=null"&gt;</span>
    <span class="hljs-comment">//这个可以修改的,设置字段的@TableField(strategy=FieldStrategy.NOT_EMPTY)</span>
    <span class="hljs-comment">//所以这个时候,为null的字段是不会更新的,也可以开启性能插件,查看sql语句就可以知道</span>
    userService.insert(user);
    
    <span class="hljs-comment">//新增所有字段,</span>
    userService.insertAllColumn(user);
    log.info(<span class="hljs-string">"新增结束"</span>);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testUpdate</span><span class="hljs-params">()</span> {
    
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"101"</span>);
    user.setName(<span class="hljs-string">"oKong-insert"</span>);
    <span class="hljs-comment">//这就是ActiveRecord的功能</span>
    user.insert();
    <span class="hljs-comment">//也可以直接 userService.insert(user);</span>

    <span class="hljs-comment">//更新</span>
    <span class="hljs-type">User</span> <span class="hljs-variable">updUser</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    updUser.setId(user.getId());
    updUser.setName(<span class="hljs-string">"okong-upd"</span>);
    
    updUser.updateById();
    log.info(<span class="hljs-string">"更新结束"</span>);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testDelete</span><span class="hljs-params">()</span> {
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"101"</span>);
    user.setName(<span class="hljs-string">"oKong-delete"</span>);
    
    user.insert();
    
    <span class="hljs-comment">//删除</span>
    user.deleteById();
    log.info(<span class="hljs-string">"删除结束"</span>);

}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testSelect</span><span class="hljs-params">()</span> {
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"201"</span>);
    user.setName(<span class="hljs-string">"oKong-selecdt"</span>);
    
    user.insert();
    
    log.info(<span class="hljs-string">"查询:{}"</span>,user.selectById());
}

}

以上就列举了常用的,官方提供了很多的通用方法:

通用方法

注意控制台的 sql输出,对比下就知道各方法之间的区别了。


对于通用代码如何注入的,可查看com.baomidou.mybatisplus.mapper.AutoSqlInjector类,这个就是注入通用的 CURD 方法的类。

AutoSqlInjector类


条件构造器

在通用的 CURD 无法满足时,这个时候 强大的条件构造器就排上用场了。主要提供了实体包装器,用于处理 sql 拼接,排序,实体参数查询等!

这里需要注意:使用的是数据库字段,不是 Java 属性!,原来使用另一款通用mapper时记得使用的是 JAVA 属性。

sql 条件拼接

这也是条件构造器最灵活的地方了。

ConditionTest.java

@RunWith(SpringRunner.class)
//SpringBootTest 是 springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。
@SpringBootTest 
@Slf4j
public class ConditionTest {
<span class="hljs-meta">@Autowired</span>
IUserService userService;

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testOne</span><span class="hljs-params">()</span> {
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span>  <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"701"</span>);
    user.setName(<span class="hljs-string">"okong-condition"</span>);
    user.insert();
    
    EntityWrapper&lt;User&gt; qryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">EntityWrapper</span>&lt;&gt;();
    
    qryWrapper.eq(User.CODE, user.getCode());
    qryWrapper.eq(User.NAME, user.getName());
    
    <span class="hljs-comment">//也可以直接 </span>

// qryWrapper.setEntity(user);

    <span class="hljs-comment">//打印sql语句</span>
    System.out.println(qryWrapper.getSqlSegment());
    
    <span class="hljs-comment">//设置select 字段 即:select code,name from </span>
    qryWrapper.setSqlSelect(User.CODE,User.NAME);
    System.out.println(qryWrapper.getSqlSelect());
    
    <span class="hljs-comment">//查询</span>
    <span class="hljs-type">User</span> <span class="hljs-variable">qryUser</span> <span class="hljs-operator">=</span> userService.selectOne(qryWrapper);
    System.out.println(qryUser);
    log.info(<span class="hljs-string">"拼接一结束"</span>);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testTwo</span><span class="hljs-params">()</span> {
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span>  <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"702"</span>);
    user.setName(<span class="hljs-string">"okong-condition"</span>);
    user.insert();
    
    EntityWrapper&lt;User&gt; qryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">EntityWrapper</span>&lt;&gt;();
    qryWrapper.where(<span class="hljs-string">"code = {0}"</span>, user.getCode())
    .and(<span class="hljs-string">"name = {0}"</span>,user.getName())
    .andNew(<span class="hljs-string">"status = 0"</span>);
    System.out.println(qryWrapper.getSqlSegment());
    <span class="hljs-comment">//等等很复杂的。</span>
    <span class="hljs-comment">//复杂的建议直接写在xml里面了,要是非动态的话 比较xml一眼看得懂呀</span>
    <span class="hljs-comment">//查询</span>
    <span class="hljs-type">User</span> <span class="hljs-variable">qryUser</span> <span class="hljs-operator">=</span> userService.selectOne(qryWrapper);
    System.out.println(qryUser);
    log.info(<span class="hljs-string">"拼接二结束"</span>);
}

}

com.baomidou.mybatisplus.mapper.Wrapper<T>类还有很多的方法,大家可以试试。
wrapper

条件参数说明

查询方式 说明
setSqlSelect 设置 SELECT 查询字段
where WHERE 语句,拼接 + WHERE 条件
and AND 语句,拼接 + AND 字段=值
andNew AND 语句,拼接 + AND (字段=值)
or OR 语句,拼接 + OR 字段=值
orNew OR 语句,拼接 + OR (字段=值)
eq 等于 =
allEq 基于 map 内容等于 =
ne 不等于 <>
gt 大于 >
ge 大于等于 >=
lt 小于 <
le 小于等于 <=
like 模糊查询 LIKE
notLike 模糊查询 NOT LIKE
in IN 查询
notIn NOT IN 查询
isNull NULL 值查询
isNotNull IS NOT NULL
groupBy 分组 GROUP BY
having HAVING 关键词
orderBy 排序 ORDER BY
orderAsc ASC 排序 ORDER BY
orderDesc DESC 排序 ORDER BY
exists EXISTS 条件语句
notExists NOT EXISTS 条件语句
between BETWEEN 条件语句
notBetween NOT BETWEEN 条件语句
addFilter 自由拼接 SQL
last 拼接在最后,例如:last("LIMIT 1")

自定义 SQL 使用条件构造器

UserDao.java加入接口方法:

/**
     * 
     * @param rowBounds 分页对象 直接传入 page 即可
     * @param wrapper 条件构造器
     * @return
     */
    List<User> selectUserWrapper(RowBounds rowBounds, @Param("ew") Wrapper<User> wrapper);

UserMapper.xml加入对应的 xml 节点:

    <!-- 条件构造器形式 -->
    <select id="selectUserWrapper" resultType="user">
        SELECT
        <include refid="Base_Column_List" />
        FROM USER
        <where>
            ${ew.sqlSegment}
        </where>
    </select>

测试类:

@Test
    public void testCustomSql() {
        User user = new User();
        user.setCode("703");
        user.setName("okong-condition");
        user.insert();
    EntityWrapper&lt;User&gt; qryWrapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">EntityWrapper</span>&lt;&gt;();
    qryWrapper.eq(User.CODE, user.getCode());
    
    Page&lt;User&gt; pageUser = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Page</span>&lt;&gt;();
    pageUser.setCurrent(<span class="hljs-number">1</span>);
    pageUser.setSize(<span class="hljs-number">10</span>);
    
    List&lt;User&gt; userlist = userDao.selectUserWrapper(pageUser, qryWrapper);
    System.out.println(userlist.get(<span class="hljs-number">0</span>));
    log.info(<span class="hljs-string">"自定义sql结束"</span>);
}

xml 形式使用 wrapper

UserDao.java

/**
     * 
     * @param rowBounds 分页对象 直接传入 page 即可
     * @param wrapper 条件构造器
     * @return
     */
    List<User> selectUserWrapper(RowBounds rowBounds, @Param("ew") Wrapper<User> wrapper);

对应的UserMapper.xml:


    <!-- 条件构造器形式 -->
    <select id="selectUserWrapper" resultType="user">
        SELECT
        <include refid="Base_Column_List" />
        FROM USER
        <where>
            ${ew.sqlSegment}
        </where>
    </select>

自定义 SQL 语句

在一些需要多表关联时,条件构造器和通用 CURD 都无法满足时,还可以自行手写 sql 语句进行扩展。注意:这都是mybatis的用法。

以下两种方式都是改造UserDao接口。

注解形式

@Select("SELECT * FROM USER WHERE CODE = #{userCode}")
    List<User> selectUserCustomParamsByAnno(@Param("userCode")String userCode);

xml 形式

List<User> selectUserCustomParamsByXml(@Param("userCode")String userCode);

同时,UserMapper.xml新增一个节点:

    <!-- 由于设置了别名:typeAliasesPackage=cn.lqdev.learning.mybatisplus.samples.biz.entity,所以 resultType 可以不写全路径了。 -->
    <select id="selectUserCustomParamsByXml" resultType="user">
        SELECT 
        <include refid="Base_Column_List"/> 
        FROM USER 
       WHERE CODE = #{userCode}
    </select>

测试类CustomSqlTest.java

@RunWith(SpringRunner.class)
//SpringBootTest 是 springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。
@SpringBootTest 
@Slf4j
public class CustomSqlTest {
<span class="hljs-meta">@Autowired</span>
UserDao userDao;

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testCustomAnno</span><span class="hljs-params">()</span> {
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"901"</span>);
    user.setName(<span class="hljs-string">"okong-sql"</span>);
    user.insert();
    List&lt;User&gt; userlist = userDao.selectUserCustomParamsByAnno(user.getCode());
    <span class="hljs-comment">//由于新增的 肯定不为null 故不判断了。</span>
    System.out.println(userlist.get(<span class="hljs-number">0</span>).toString());
    log.info(<span class="hljs-string">"注解形式结束------"</span>);
}

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testCustomXml</span><span class="hljs-params">()</span> {
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"902"</span>);
    user.setName(<span class="hljs-string">"okong-sql"</span>);
    user.insert();
    List&lt;User&gt; userlist = userDao.selectUserCustomParamsByXml(user.getCode());
    <span class="hljs-comment">//由于新增的 肯定不为null 故不判断了。</span>
    System.out.println(userlist.get(<span class="hljs-number">0</span>).toString());
    log.info(<span class="hljs-string">"xml形式结束------"</span>);
}

}

注意事项

在使用spring-boot-maven-plugin插件打包成springboot运行 jar 时,需要注意下,由于springboot的 jar 扫描路径方式问题,会导致别名的包未扫描到,所以这个只需要把mybatis默认的扫描设置为SpringbootVFS实现。

直接修改spring-mybatis.xml文件:

  <!--mybatis-->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 自动扫描 mapper.xml 文件,支持通配符 -->
        <property name="mapperLocations" value="classpath:mapper/**/*.xml"/>
        <!-- 配置文件,比如参数配置 (是否启动驼峰等)、插件配置等 -->
        <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
        <!-- 启用别名,这样就无需写全路径类名了,具体可自行查阅资料 -->
        <property name="typeAliasesPackage" value="cn.lqdev.learning.mybatisplus.samples.biz.entity"/>
        <!-- MP 全局配置注入 -->
        <property name="globalConfig" ref="globalConfig"/>
        <!-- 设置 vfs 实现,避免路径扫描问题 -->
        <property name="vfs"  value="com.baomidou.mybatisplus.spring.boot.starter.SpringBootVFS"></property>
    </bean>

分页插件、性能分析插件

mybatis 的插件机制使用起来是很简单的,只需要注册即可。

mybatis-config.xml

    <plugins>
      <!-- SQL 执行性能分析,开发环境使用,线上不推荐。 -->
      <plugin interceptor="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"></plugin>
      <!-- 分页插件配置 -->
      <plugin interceptor="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></plugin>
    </plugins>

分页测试类 (性能分析,配置后可以输出 sql 及取数时间):

@RunWith(SpringRunner.class)
//SpringBootTest 是 springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。
@SpringBootTest 
@Slf4j
public class PluginTest {
<span class="hljs-meta">@Autowired</span>
IUserService userService;

<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">testPagination</span><span class="hljs-params">()</span> {
    Page&lt;User&gt; page = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Page</span>&lt;&gt;();
    <span class="hljs-comment">//每页数</span>
    page.setSize(<span class="hljs-number">10</span>);
    <span class="hljs-comment">//当前页码</span>
    page.setCurrent(<span class="hljs-number">1</span>);
    
    <span class="hljs-comment">//无条件时</span>
    Page&lt;User&gt; pageList = userService.selectPage(page);
    System.out.println(pageList.getRecords().get(<span class="hljs-number">0</span>));
    
    <span class="hljs-comment">//新增数据 避免查询不到数据</span>
    <span class="hljs-type">User</span> <span class="hljs-variable">user</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">User</span>();
    user.setCode(<span class="hljs-string">"801"</span>);
    user.setName(<span class="hljs-string">"okong-Pagination"</span>);
    user.insert();
    <span class="hljs-comment">//加入条件构造器</span>
    EntityWrapper&lt;User&gt; qryWapper = <span class="hljs-keyword">new</span> <span class="hljs-title class_">EntityWrapper</span>&lt;&gt;();
    <span class="hljs-comment">//这里也能直接设置 entity 这是条件就是entity的非空字段值了</span>

// qryWapper.setEntity(user);
// 这里建议直接用 常量
// qryWapper.eq(User.CODE, user.getCode());
pageList = userService.selectPage(page, qryWapper);
System.out.println(pageList.getRecords().get(0));
log.info("分页结束");
}

}

性能插件体现,控制台输出:

 Time4 ms - ID:cn.lqdev.learning.mybatisplus.samples.biz.dao.UserDao.selectPage
 Execute SQLSELECT id AS id,code,`name`,`status`,gmt_create AS gmtCreate,gmt_modified AS gmtModified FROM user WHERE id=1026120705692434433 AND code='801' AND `name`='okong-Pagination' LIMIT 0,10

公共字段自动填充

通常,每个公司都有自己的表定义,在《阿里巴巴 _Java_ 开发手册》中,就强制规定表必备三字段:id, gmt_create, gmt_modified。所以通常我们都会写个公共的拦截器去实现自动填充比如创建时间和更新时间的,无需开发人员手动设置。而在MP中就提供了这么一个公共字段自动填充功能

设置填充字段的填充类型

User.java

    /**
     * 创建时间
     */
    @TableField(fill=FieldFill.INSERT)
    private Date gmtCreate;
    /**
     * 修改时间
     */
    @TableField(fill=FieldFill.INSERT_UPDATE)
    private Date gmtModified;

注意这里是可以在代码生成器里面配置规则的,可自动配置,详见代码生成器类。

定义处理类

MybatisObjectHandler.java

public class MybatisObjectHandler extends MetaObjectHandler{
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">insertFill</span><span class="hljs-params">(MetaObject metaObject)</span> {
    <span class="hljs-comment">//新增时填充的字段</span>
    setFieldValByName(<span class="hljs-string">"gmtCreate"</span>, <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(), metaObject);
    setFieldValByName(<span class="hljs-string">"gmtModified"</span>, <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(), metaObject);
    
}

<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">updateFill</span><span class="hljs-params">(MetaObject metaObject)</span> {
    <span class="hljs-comment">//更新时 需要填充字段</span>
    setFieldValByName(<span class="hljs-string">"gmtModified"</span>, <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(), metaObject);
}

}

同时修改springb-mybatis.xml文件,加入此配置:

    <bean id="globalConfig" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
        <!--
            AUTO->`0`("数据库 ID 自增")QW
             INPUT->`1`(用户输入 ID")
            ID_WORKER->`2`("全局唯一 ID")
            UUID->`3`("全局唯一 ID")
        -->
        <property name="idType" value="2" />
        <property name="metaObjectHandler" ref="mybatisObjectHandler"></property>
    </bean>
<span class="hljs-tag">&lt;<span class="hljs-name">bean</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"mybatisObjectHandler"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cn.lqdev.learning.mybatisplus.samples.config.MybatisObjectHandler"</span>/&gt;</span>

这个时候再新增或者修改,对应时间就会进行更新了。

 Time31 ms - ID:cn.lqdev.learning.mybatisplus.samples.biz.dao.UserDao.insert
 Execute SQLINSERT INTO user ( id, code, `name`, gmt_create,gmt_modified ) VALUES ( 1026135016838037506, '702', 'okong-condition', '2018-08-05 23:57:07.344','2018-08-05 23:57:07.344' )

相关资料

  1. MP 官网:http://mp.baomidou.com

总结

本文主要列举了开发过程中常用的操作数据库的方法及相关配置。应该可以应付百分之八十以上的需求了吧。之后有时间,会进行补充的,比如自定义插件、大批量数据的写法等。

最后

若文中有错误或者遗漏之处,还望指出,共同进步!

老生常谈

  • 个人 QQ:499452441
  • 微信公众号:lqdevOps

公众号

个人博客:http://blog.lqdev.cn

完整示例:https://gitee.com/oKong/mybatis-plus-samples

原文地址:http://blog.lqdev.cn/2018/08/06/%E6%97%A5%E5%B8%B8%E7%A7%AF%E7%B4%AF/mybatis-plus-guide-one/