Mybatis plus简单使用

一、快速入门

导入依赖,具体版本根据自己需要可以选择:

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>Latest Version</version>
        </dependency>

导入mybatis-plus就不用导入mybatis。

数据源配置,这里直接使用spring boot 自带的数据源。

spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/db_test/useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

mybatis-plus中,提供了一个BaseMapper,这个mapper整合了单表的CRUD操作,只要使用Mapper集成,就可以直接使用,同时集成了分页的插件,不过要配置拦截器才能使用。主要扫描接口,@MapperScan("com.mg.mapper"):

/*
 * Copyright (c) 2011-2020, hubin ([email protected]).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.core.mapper;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Param;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;

/*

               :`
                    .:,
                     :::,,.
             ::      `::::::
             ::`    `,:,` .:`
             `:: `::::::::.:`      `:';,`
              ::::,     .:::`   `@++++++++:
               ``        :::`  @+++++++++++#
                         :::, #++++++++++++++`
                 ,:      `::::::;'##++++++++++
                 .@#@;`   ::::::::::::::::::::;
                  #@####@, :::::::::::::::+#;::.
                  @@######+@:::::::::::::.  #@:;
           ,      @@########':::::::::::: .#''':`
           ;##@@@+:##########@::::::::::: @#;.,:.
            #@@@######++++#####'::::::::: .##+,:#`
            @@@@@#####+++++'#####+::::::::` ,`::@#:`
            `@@@@#####++++++'#####+#':::::::::::@.
             @@@@######+++++''#######+##';::::;':,`
              @@@@#####+++++'''#######++++++++++`
               #@@#####++++++''########++++++++'
               `#@######+++++''+########+++++++;
                `@@#####+++++''##########++++++,
                 @@######+++++'##########+++++#`
                @@@@#####+++++############++++;
              ;#@@@@@####++++##############+++,
             @@@@@@@@@@@###@###############++'
           @#@@@@@@@@@@@@###################+:
        `@#@@@@@@@@@@@@@@###################'`
      :@#@@@@@@@@@@@@@@@@@##################,
      ,@@@@@@@@@@@@@@@@@@@@################;
       ,#@@@@@@@@@@@@@@@@@@@##############+`
        .#@@@@@@@@@@@@@@@@@@#############@,
          @@@@@@@@@@@@@@@@@@@###########@,
           :#@@@@@@@@@@@@@@@@##########@,
            `##@@@@@@@@@@@@@@@########+,
              `+@@@@@@@@@@@@@@@#####@:`
                `:@@@@@@@@@@@@@@##@;.
                   `,'@@@@##@@@+;,`
                        ``...``

 _ _     /_ _ _/_. ____  /    _
/ / //_//_//_|/ /_\  /_///_/_\      Talk is cheap. Show me the code.
     _/             /
 */

/**
 * <p>
 * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
 * </p>
 * <p>
 * 这个 Mapper 支持 id 泛型
 * </p>
 *
 * @author hubin
 * @since 2016-01-23
 */
public interface BaseMapper<T> {

    /**
     * <p>
     * 插入一条记录
     * </p>
     *
     * @param entity 实体对象
     */
    int insert(T entity);

    /**
     * <p>
     * 根据 ID 删除
     * </p>
     *
     * @param id 主键ID
     */
    int deleteById(Serializable id);

    /**
     * <p>
     * 根据 columnMap 条件,删除记录
     * </p>
     *
     * @param columnMap 表字段 map 对象
     */
    int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

    /**
     * <p>
     * 根据 entity 条件,删除记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 删除(根据ID 批量删除)
     * </p>
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

    /**
     * <p>
     * 根据 ID 修改
     * </p>
     *
     * @param entity 实体对象
     */
    int updateById(@Param(Constants.ENTITY) T entity);

    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param entity        实体对象 (set 条件值,不能为 null)
     * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
     */
    int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

    /**
     * <p>
     * 根据 ID 查询
     * </p>
     *
     * @param id 主键ID
     */
    T selectById(Serializable id);

    /**
     * <p>
     * 查询(根据ID 批量查询)
     * </p>
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

    /**
     * <p>
     * 查询(根据 columnMap 条件)
     * </p>
     *
     * @param columnMap 表字段 map 对象
     */
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

    /**
     * <p>
     * 根据 entity 条件,查询一条记录
     * </p>
     *
     * @param queryWrapper 实体对象
     */
    T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询总记录数
     * </p>
     *
     * @param queryWrapper 实体对象
     */
    Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 entity 条件,查询全部记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录
     * 注意: 只返回第一个字段的值
     * </p>
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 entity 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param page         分页查询条件(可以为 RowBounds.DEFAULT)
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param page         分页查询条件
     * @param queryWrapper 实体对象封装操作类
     */
    IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}

在Mapper中直接集成即可:

package com.mg.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mg.pojo.User;

/**
 * 实现基本的接口,就可以使用CRUD
 */
public interface UserMapper extends BaseMapper<User> {
}

 简单一波测试:

mybatis-plus,已经帮忙写好了单表的CRUD和方法。

二、日志配置

所有的SQL都是不可见的,需要查看SQL执行顺序等等。

#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

可以根据日期,去分析相关问题。

三、CRUD扩展

1、插入,ID会自动添加 

@Test
    public void test01(){
        User user = new User();
        user.setName("LMR");
        user.setAge(4);
        user.setEmail("[email protected]");
        int insert = userMapper.insert(user);
        System.out.println(insert);
        System.out.println(user.toString());
    }

 主键生成策略:

  • UUID
  • 自增ID
  • 雪花算法(分布式)
  • 中间件生成(redis、zookeeper)

雪花算法:

是Twitter开源的分布式ID生成算法,结果是一个Long的ID。核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5bit是数据中心,5bit是机器ID),12bit作为毫秒内的流水号(意味着每个节点在每秒可以产生4096个ID),最后一个符号位永远是0。

可以配置ID生成策略:

    @TableId(type = IdType.AUTO)
    private Long id;

 枚举:

/*
 * Copyright (c) 2011-2020, hubin ([email protected]).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baomidou.mybatisplus.annotation;

import lombok.Getter;

/**
 * <p>
 * 生成ID类型枚举类
 * </p>
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
public enum IdType {
    /**
     * 数据库ID自增
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型
     */
    NONE(1),
    /**
     * 用户输入ID
     * 该类型可以通过自己注册自动填充插件进行填充
     */
    INPUT(2),

    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 全局唯一ID (idWorker)
     */
    ID_WORKER(3),
    /**
     * 全局唯一ID (UUID)
     */
    UUID(4),
    /**
     * 字符串全局唯一ID (idWorker 的字符串表示)
     */
    ID_WORKER_STR(5);

    private int key;

    IdType(int key) {
        this.key = key;
    }
}

2、更新操作

    @Test
    public void test02(){
        User user = new User();
        user.setId(5L);
        user.setName("MG BASE GOGO!");
        userMapper.updateById(user);
    }

自动填充:

例如修改时间、添加时间都需要自动填充进去,不能手动更新。

  • 数据库级别的修改:在表中新增字段,不太建议使用(测试中发现,就算更显操作了,但是值没有改变,则不会填充时间)
  • 代码级别的修改,编写处理器进行处理。
        @TableField(fill = FieldFill.INSERT)
        private Date createTime;
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date updateTime;
    package com.mg.handler;
    
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.security.DenyAll;
    import java.util.Date;
    
    @Component
    @Slf4j
    public class MyMeteObjectHandler implements MetaObjectHandler {
    
        /**
         * 插入时候的填充策略
         * @param metaObject
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill。。。");
            //字段、值、元数据
            this.setFieldValByName("createTime", new Date(), metaObject);
            this.setFieldValByName("updateTime", new Date(), metaObject);
        }
    
        /**
         * 更新时候的填充策略
         * @param metaObject
         */
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updateTime", new Date(), metaObject);
        }
    }
    

乐观锁/悲观锁:

  • 乐观锁:总是认为不会出现问题,所以不会去上锁,如果出现了问题,就在再次更新值 version字段
  • 悲观锁:认为总是会出现问题,不论干什么都会先上锁在操作

mybatis-plus乐观锁插件:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

下面看看怎么配置:

1、数据库增加字段,version,默认值是1

 2、实体类增加version字段和@Version注解

    @Version
    private Integer version;

3、注册组件(新版本MybatisPlus 为了统一管理插件,使用了一个 统一的插件管理类,只需要注册一个Bean就行了 MybatisPlusInterceptor)

package com.mg.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@MapperScan("com.mg.mapper")
@Configuration
public class MybatisPlusConfig {

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInnerInterceptor(){
        return new OptimisticLockerInterceptor();
    }

}

4、测试,这里user更新就不会成功,因为版本已经被覆盖了 

 @Test
    public void test04(){
        //线程1
        User user = userMapper.selectById(1L);
        user.setName("123");
        user.setEmail("[email protected]");
        //线程2
        User user2 = userMapper.selectById(1L);
        user2.setName("123_2");
        user2.setEmail("[email protected]_2");
        userMapper.updateById(user2);
        userMapper.updateById(user);
    }

3、查询操作

简单查询:

 @Test
    public void test05(){
        //单个查询
        User user = userMapper.selectById(1L);
        System.out.println("单个查询:" + user.toString());
        //批量查询
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(u ->{
            System.out.println("批量:" + u.toString());
        });
        //条件查询 使用map
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("name", "123_2");
        paramMap.put("age", 18);
        List<User> users1 = userMapper.selectByMap(paramMap);
        users1.forEach(u->{
            System.out.println("批量:" + u.toString());
        });
    }

分页查询:

mybatis-plus 内置分页插件:(如果是线上的话,一般情况下回自己手动写 count()查询的sql)

1、配置拦截器组件即可

    // 旧版
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }
    @Test
    public void test06(){
        //当前页、页面大小
        Page<User> page = new Page<>(1, 5);
        IPage<User> userIPage = userMapper.selectPage(page, null);
        userIPage.getRecords().forEach(u->{
            System.out.println("批量:" + u.toString());
        });
    }

4、删除

物理删除:

逻辑删除:

1、增加一个deleted字段

2、增加属性

    @TableLogic
    private Integer deleted;

3、配置组件

    //逻辑删除
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }
#逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

4、测试,生成的sql不会查询出来

    @Test
    public void test07(){
        userMapper.deleteById(1L);
    }

四、性能分析插件

主要在平时使用的时候,遇到一些慢sql,mybatis-plus也提供了这样的插件,如果超过设定时间,则停止运行。发现新版本已经没有这个功能了,可能是因为提供这样功能的组件太多了,就给去掉了。

1、导入插件

    @Profile({"dev","test"})
    @Bean
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        //最大执行时间,超过则不执行
        performanceInterceptor.setMaxTime(1);
        //sql格式化
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }

2、测试使用,超出设置时间,就会抛出异常

五、条件构造器

Wapper 条件构造器,十分重要,一些复杂的条件,可以使用这个替代。

1、测试1

    @Test
    public void test01(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNotNull("name").isNotNull("email").ge("age", 12);
        List<User> users = userMapper.selectList(queryWrapper);
        users.forEach(u->{
            System.out.println(u);
        });
    }

 2、测试2,查询一个 selectOne

    @Test
    public void test02(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", "Tom");
        User user = userMapper.selectOne(queryWrapper);
        System.out.println(user);
    }

3、测试3,查询数量selectCount

    @Test
    public void test03(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.between("age", "1", "30");
        int n = userMapper.selectCount(queryWrapper);
        System.out.println(n);
    }

 4、测试4,模糊查询

    @Test
    public void test04(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.notLike("name", "e")
                .likeLeft("name", "e")
                .likeRight("email", "1");
        List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }

5、测试5,嵌入sql

    @Test
    public void test05(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("id", "select id from user where id<3");
        List<Object> objects = userMapper.selectObjs(queryWrapper);
        objects.forEach(System.out::println);
    }

 6、测试6,排序

    @Test
    public void test06(){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("id");
        List<Object> objects = userMapper.selectObjs(queryWrapper);
        objects.forEach(System.out::println);
    }

六、代码自动生成器

引入依赖:

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.0.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

生成代码:

package com.mg;
import java.util.Arrays;
import java.util.HashMap;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.annotation.DbType;


import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;


/**
 * 代码生成器
 */
public class MGCode {
    public static void main(String[] args) {
        //构建代码生成器对象
        AutoGenerator mpg = new AutoGenerator();
        //配置策略
        //1、全局配置
        GlobalConfig gc = new GlobalConfig();
        //设置生成地址
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("mg");
        //是否打开资源管理器
        gc.setOpen(false);
        //是否覆盖
        gc.setFileOverride(true);
        //设置接口名字
        gc.setServiceName("%sService");
        //主键策略
        gc.setIdType(IdType.ID_WORKER);
        //日期类型
        gc.setDateType(DateType.ONLY_DATE);
        //是否开启文档
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        //2、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/db_test?useSSL=false&useUnicode=true&characterEncoding=utf-8");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);


        //3、配置一些包
        PackageConfig pc = new PackageConfig();
        //模块名称
        pc.setModuleName("wjf");
        //包名
        pc.setParent("com.mg");
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        //4、策略配置
        StrategyConfig strategy = new StrategyConfig();
        //设置需要映射的表明  tb_user
        strategy.setInclude("user", "tb_user");
        //规则 驼峰
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //Lombok
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        //逻辑删除字段
        strategy.setLogicDeleteFieldName("deleted");
        //自动填充配置
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        strategy.setTableFillList(Arrays.asList(createTime, updateTime));
        //乐观锁
        strategy.setVersionFieldName("version");
        //controller 相关
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);//localhost:8080/hello_id_2
        mpg.setStrategy(strategy);

        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        //执行生成
        mpg.execute();
    }
}

生成的代码结构:

 本文章是基于B站博主,狂神说的,所以mybatis-plus版本比较老,学习新版本的,可以看官网,里面的东西写的很清楚。MyBatis-Plus

猜你喜欢

转载自blog.csdn.net/liming0025/article/details/121065184