MyBatis-Plus (baomidou.com)

一 MyBatis-Plus简介

  1. 增强工具。只做增强不做改。

    1. 可以直接在mybatis的基础上整合mybatis-plus。此时并不会影响mybatis的功能,即mybatis原来的功能都在,该怎么用还怎么用。锦上添花的是还能使用mybatis-plus提供的:通用的mapper、通用的service、在不编写任何sql语句的基础上快速完成单表的CRUD、批量操作、逻辑删除、分页、优秀插件的使用、多数据源的配置等待功能。
  2. 框架结构
    1. 右半部分:mybatis-plus的组成部分,共同支持mybatis-plus的功能实现

      1. mybatis-plus-boot-starter:mybatis-plus本身的启动器
      2. annotation:注解部分
      3. extension:扩展部分
      4. core:核心部分
      5. generator:代码生成部分
    2. 左半部分:展示了mybatis-plus该如何来实现功能
      1. 第一步:Scan Entity:扫描实体类

        1. 在开发过程中,为什么不需要手写sql语句(mybatis需要)呢?因为mybaits-plus中sql语句都是动态生成的,所以第一步要扫描要操作的实体类(当前操作的表由实体类决定)。
      2. 第二步:Reflection extraction:反射抽取
        1. 经过实体类的扫描以后,通过反射抽取实体类中的属性。
      3. 第三步:Analysis Table Name Column
        1. 抽取出实体类中的属性以后,分析实体类和表之间的关系、分析实体类属性与表字段之间的关系。
      4. 第四步:SQL: Insert Update Delete Select:当前调用的CRUD方法
        1. 分析完成以后,根据当前我们调用的CRUD方法,生成相对应的sql语句。

          1. 调用的CRUD方法?因为mybatis-plus提供了通用的mapper、通用的service。
      5. 第五步:Injection Mybatis Container:sql语句注入到mybatis容器中,从而实现最终的功能。

二 基本功能

1 通用mapper

  1. 概述

    1. 通用mapper中包含的CRUD方法,它们的返回值都是int类型的,指向的是受影响的行数。
    2. List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
      1. 单独使用mybatis的工程:mybatis中我们的查询方法可以返回实体类对象,也可以查询并返回一个List集合,也可以查询并返回一个map集合。
      2. 使用mybatis-plus的工程:同理。也可以。
  2. 入门案例
    1. 第一步:mysql

      1. 第1步:创建数据库入表

        1. id,主键,bigint(20)。因为在通过mybatis-plus进行数据插入的时候,它默认用雪花算法来生成id,这样一来id的长度会比较长,所以这里使用的是bigint而非int。
    2. 第二步:idea
      1. 第1步:创建spring boot工程
      2. 第2步:pom.xml
        1. 第a步:lombok依赖。
      3. 第3步:idea插件安装
        1. 第a步:idea安装lombok插件。
      4. 第4步:application.yml
        1. 第a步:数据源类型:type: com.zaxxer.hikari.HikariDataSource(此类型:springboot中默认使用的数据源类型)
        2. 第b步:jdbc:mysql://localhost:3306/mysql?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
          1. characterEncoding:连接数据库、操作数据库时使用的编码格式。
          2. serverTimezone=GMT%2B8:中国时区的配置(mysql8独有配置)
          3. useSSL=false:mysql5和mysql8都要使用此参数
      5. 第5步:编码
        1. 第a步:实体类User.java:因为数据库中的表要和实体类做映射关系;

          1. private Long id:因为数据库表中id使用的是bigint类型,按照数据类型的范围来说,实体类这里最好使用Long类型进行映射(接收)。
          2. @Data :这是lombok注解。虽然在当前实体类中看不到构造器(有参、无参)、get/set方法,但是经过maven 》complie把当前的工程编译以后,在target 》classes 》User.class会看到构造器、get/set方法、equal方法、tostring方法
          3. maven打包错误: Failed to execute goal org.apache.maven.pluginsmaven-resources-plugin3.2.0resources
            1. pom.xml中springboot版本:<version>2.6.3</version>
            2. pom.xml中jdk版本:<java.version>8</java.version>
        2. 第b步:添加mapper接口:UserMapper.java,并使用mybatis-plus提供的通用mapper
          1. 单独使用mybatis的工程:mapper接口中的方法和sql语句都是需要我们手动去写的。
          2. 使用mybatis-plus的工程:使用mybatis-plus提供的通用mapper、通用service功能,快速实现单表的CRUD。
          3. public interface UserMapper extends BaseMapper<User>:BaseMapper中包含了很多很多mybatis-plus提供方法
            1. CRUD方法
        3. 第c步:启动类
          1. 单独使用mybatis的工程:设置mapper接口所在的包、映射文件所在的包。
          2. 使用mybatis-plus的工程:同样需要。
          3. //用于扫描mapper接口所在的包
            //或者所用于扫描指定包下的mapper接口
            @MapperScan("com.atguigu.mapper")
        4. 第d步:测试类
          1. 单独使用mybatis的工程:首先,需要在UserMapper中创建接口方法。然后,在对应的映射文件中编写对应的Sql语句。
          2. 使用mybatis-plus的工程:不用写接口方法,不用写sql语句。首先,继承mybatis-plus提供的模板(通用)XxxMapper。然后,调用相应的crud方法即可。
          3. 原理:因为在启动类中加入了@MapperScan("com.atguigu.mapper")
            ,从而实现把指定包下面的所有的mapper接口所动态生成的代理类交给ioc容器来管理,所以在测试类中可以对ioc容器中管理的组件进行自动装配了,这里我们自动装配UserMapper这个Bean。
          4. 报错:private UserMapper userMapper;中的userMapper有红色波浪线。首先上面分析的(原理)是没有任何问题的。因为@MapperScan("com.atguigu.mapper")扫描的包下都是接口,但在ioc容器中只能存在类所对应的bean,不能存在接口所对应的bean,所以如上面所说是将mapper接口所动态生成的代理类交给ioc容器来管理。而在idea中,它认为UserMapper是一个接口,在idea的编译后半段,idea认为这是无法进行自动装配的,所以有红色波浪线。但注意,在运行接口是没有任何问题的。
          5. 运行报错:(355条消息) 【Java异常】idea 报错:无效的目标发行版:17 的解决办法_No8g攻城狮的博客-CSDN博客_无效的源发行版17
          6. selectList(Wrapper wrapper):Wrapper为条件构造器。也就是说当我们在查询数据时,如果我们有查询条件的话,我们就可以通过Wrapper来实现。如果没有条件的话,就写null。//selectList()根据MP内置的条件构造器查询一个list集合,null表示没有条件,即查询所有
          7. 报错:Unknown column 'id' in 'field list':表没有这个字段
        5. 第e步:问题分析
          1. 问题1:解决private UserMapper userMapper;中的userMapper有红色波浪线的问题,方法:在UserMapper.java中加入@Repository注解。@Repository注解的作用是将当前类或者接口标识为一个持久层组件。
          2. 问题2:整个过程中我们没有告诉mybaits要查询哪个表?那它是怎么有知道的呢?因为BaseMapper<User>中的泛型起了作用,User对应的就是user表。为什么会去查询id,name,email呢?因为泛型User中我们设置了属性id,name,email,所以有SELECT id,name,age,email FROM user。总结,mybatis操作的表和字段,是由实体类(泛型)中的类名和属性决定的。
          3. 问题3:mybatis-plus查询user表以后,就把表中对应字段的值,赋值给了我们实体类中相对应的属性。
      6. 第6步:添加日志功能,查询mybatis-plus帮我们生成的sql语句
        1. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl:使用默认的(自带)的就行。
    1. BaseMapper.insert(user)

      1. 获取自动递增的id=14240358972034957。为什么这个自动递增的主键这么长(实体类属性Long类型,表字段bigint类型)?这个并不是我们所使用的自动递增的主键。那这个主键到底是怎么样生成的呢?首先,在mybaits-plus中默认使用雪花算法来生成id值。
      2. 生成sql语句:INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
        1. User.java对应的是表名user
        2. User.java中的id、name、age、email属性对应的是表的字段
    1. BaseMapper.deleteById(1475754982694199298L);

      1. 这里如果没有加L的话报错,因为1475754982694199298果断已经超过了int的范围,所以我们在后面加上一个L字,表示它是一个Long类型的数据。
    2. BaseMapper.deleteByMap(map);
      1. //根据map集合中所设置的条件删除记录
        //DELETE FROM user WHERE name = ? AND age = ?
    3. BaseMapper.deleteBatchIds(idList);
      1. //通过多个id批量删除
        List<Long> idList = Arrays.asList(1L, 2L, 3L);,因为id是Long(对应数据库中的bigint)类型的。
        //DELETE FROM user WHERE id IN ( ? , ? , ? )
    1. BaseMapper.updateById(user);

      1. //UPDATE user SET name=?, age=? WHERE id=?。如果某个属性没有赋值,那么这表中的这个字段不会被更新。
    1. BaseMapper.selectById(4L);

      1. //SELECT id,name,age,email FROM user WHERE id=?。返回id=xxx用户信息。
    2. BaseMapper.selectBatchIds(idList);
      1. //根据多个id查询多个用户信息

        //SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )

    3. BaseMapper.selectByMap(map);
      1. //通过map条件查询用户信息
        //SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
    4. BaseMapper.selectList(null);
      1. //查询所有用户信息
        //SELECT id,name,age,email FROM user
  3. 测试自定义功能、执行自定义sql
    1. 应用场景:BaseMapper中的基本方法无法满足我们的CRUD需求

      1. 场景1:mybaits-plus实现两个表的联合查询。
      2. 场景2:mybaits-plus执行自定义的sql语句。
    2. 原理:因为mybaits-plus是在mybatis的基础之上只做增强而不做改变,所以我们之前单独使用mybatis时怎么实现,现在我们就应该怎么实现。
    3. 功能"集合":mybatis
    4. "神的"冰箱:mybatis
    5. 详细步骤
      1. 回忆,单独使用mybatis的工程:

        1. 第一步:创建Mapper接口。
        2. 第二步:创建映射文件,在里面编写sql语句。
      2. 第一步:在已经有的Mapper接口:UserMapper.java(extends BaseMapper<User>),创建接口方法
        1. 第1步:声明接口方法:Map<String,Object> selectMapById(Long id)
        2. 完整的接口文件:
          @Repository
          public interface UserMapper extends BaseMapper<User> {// 根据id查询用户信息,返回map集合Map<String,Object> selectMapById(Long id);
          }
      3. 第二步:创建映射文件
        1. 写在哪里?application.yml中通过mybatis-plus.mapper-location=xxx进行配置,这个属性mybatis-plus已经给我们配置了一个默认的位置:classpath*:/mapper/**/*.xml(类路径下的,mapper目录下的,任意子目录下的,任意.xml文件,都是会被看成映射文件)。
        2. 自定义位置?如mybatis-plus.mapper-location=xxx
        3. 如何编写?
          1. 第1步:XxxMapper.xml名称要和UserMapper.java接口名称中Xxx=User。
          2. 第2步:namespace的值是UserMapper.java的绝对路径。
          3. 第3步:<select>标签
            1. 第a步:id="selectMapById(接口方法名称)"
            2. 第b步:resultType="map"。因为mybatis中有类型别名的说法,而这里的"map"就是mybatis(默认)自定义的HashMap集合的类型别名,所以我们这里直接写"map"即可。
            3. 第c步:编写sql语句。
          4. 完整映射文件?
            <?xml version="1.0" encoding="UTF-8" ?>
            <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
            <mapper namespace="com.atguigu.mapper.UserMapper"><!--Map<String,Object> selectMapById(Long id)--><select id="selectMapById" resultType="map">select id,name ,age,email from user where id=#{id}</select>
            </mapper>
      4. 第三步:编写测试类
        @Test
        public void selectMapById(){Map<String, Object> map = userMapper.selectMapById(1L);System.out.println(map);
        }
    6. 总结:
      1. 从这个案例大家也能够看出来,mybatis-plus其实就是mybtis的一个增强工具,mybatis-plus并不会去改mybatis原有的功能。

2 通用service

  1. 概述

    1. 可以使用mybatis-plus提供的通用Mapper中的方法对表进行CRUD操作,同理也可以使用mybatis-plus提供的通用service中的方法对表进行CRUD操作。
    2. 通用service与通用Mapper的区别与联系
      1. 联系(官网):通用 Service CRUD 封装IService接口,进一步封装 CRUD ,而底层通过调用通用的Mapper实现CRUD
      2. 区别(官网):方法名前缀:查(get/list)删(remove)分页(page)。
      3. 总结(CSDN):Mapper方式,可以实现简单的CRUD。Service方式,可以实现更加丰富的CRUD,但是必须依赖Mapper,也就是必须编写mapper接口。Service简直是BaseMapper的大扩充,不但包含了所有基本方法,还加入了很多批处理功能。
    3. IService的原理?同上
  2. 使用
    1. 方案

      1. 方案1:直接使用ServiceImpl<M extends BaseMapper<T>,T>。但不建议这样去用,因为以后所遇到的业务逻辑是非常复杂的,开发人员需要根据自己的需求来编写自已的业务逻辑代码,所以mybatis-plus提供的通用ServiceImpl一定是无法满足所有的业务逻辑的需求的。
      2. 方案2:参考UserMapper.java。可以自定义一个UserService,来继承通用ServiceImpl。这样即可以使用通用ServiceImpl提供的功能,也能够自定义自己的业务逻辑功能。
    2. 快速入门:自定义XxxServiceImpl
      1. 第一步:创建实体类User.java
      2. 第二步:创建自定义的Mapper:创建、注入、配置扫描
        public interface UserMapper extends BaseMapper<User> {
        }
      3. 第三步:创建自定义Service接口:
        public interface UserService extends IService<User> { }
      4. 第四步:创建自定义实现类:创建、注入
        /*** ServiceImpl实现了IService,提供了IService中基础功能的实现* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现*/
        @Service
        public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
      5. 第五步:测试
        1. 测试1:long count = userService.count();,总记录数
        2. 测试2:userService.saveBatch(users);,批量添加(通用Mapper中就没有)

3 常用注解

  1. @TableName:表名与实体类型名的映射关系

    1. 需求:User.java与t_user表映射
    2. 方案1:局部配置:@TableName
    3. 方案2:全局配置,application.yml,配置实体类对应的表的统一“前缀t_”:
                  # 配置MyBatis-Plus操作表的默认前缀
                  table-prefix: t_
  2. @TableId:主键与实体类(主键)属性的映射关系、表主键的生成策略
    1. 需求:表的主键必须取名为id,实体类的属性(主键)必须取名为id
    2. 方案:@TableId,实体类属性uid,表字段uid
    3. 属性1:value,实体类属性id,表字段uid
    4. 属性2:type,主键生成策略,mybatis-plus中主键id默认的生成策略是雪花算法
      1. 主键生成策略之雪花算法::type="IdType.none" 或 type="IdType.ACCESS_ID"
      2. 主键生成策略之mysql中的字段自动递增:type="IdType.AUTO"
      3. 注意:不管在哪个主键生成策略下,如果在调用save方法时Entity设置(set)了主键id,那么mybatis-plus就不会用任何主键生成策略,而直接使用Entity设置(set)的主键值。
    5. 通过全局配置配置主键生成策略
      1. 需求:统一指定主键生成策略
      2. 方案:application.yml
                   # 配置MyBatis-Plus的主键策略
                   id-type: auto,总是:最大的id值 + 1
    6. 雪花算法
      1. 应用场景:
        1. 场景1:非常适合使用在分布式架构的项目中
          1. 肯定不会重复:即能够保证不同表的主键的不重复性,也能相同表的主键的有序性(相当于自增排序)。
      2. 核心思想:
  3. @TableField
    1. 需求:实体类属性(非主键)名称与数据库字段(非主键)名称不一致
    2. 方案:@TableField
    3. 注意:mybatis-plus默认配置,表中的下划线字段(非主键)名 》实体类的驼峰属性(非主键)名
  4. @TableLogic:逻辑删除
    1. 业务:用户想要恢复已经被删除过的数据
    2. 需求:逻辑删除
    3. 功能“集合”:逻辑删除
    4. “神的”工具:mybatis-plus   @TableLogic
    5. 原理:增加字段,0、1表示数据状态,秒变修改功能
    6. 注意:当前的逻辑删除自动转化为修改操作,当前的查询功能会自动查询当前未属性删除状的数据。

4 条件构造(器):构造需要满足的条件

  1. 概述

    1. wrapper的作用:封装查询、修改、删除的sql语句中的条件
    2. wrapper的组织构架图:
      1. Wrapper : 条件构造抽象类,最顶端父类

        1. AbstractWrapper : 用于查询条件封装,生成 sql 的 where

          1. QueryWrapper : 查询条件封装

            1. 封装1:查询的条件
            2. 封装2:删除的条件
            3. 可实现:修改功能
          2. UpdateWrapper : Update 条件封装
            1. 封装1:修改的条件
            2. 封装2:修改的字段
          3. AbstractLambdaWrapper : 使用Lambda 语
            1. LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper

              1. 封装1:查询的条件
              2. 封装2:删除的条件
              3. 可实现:修改功能
            2. LambdaUpdateWrapper : Lambda 更新封装Wrapper
              1. 封装:修改的条件
  2. QueryWrapper使用
    1. 组装查询条件:

      @Test
      public void test01(){//查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like("name", "a").between("age", 20, 30).isNotNull("email");//注意1:username、ageemail为数据库表的字段名//注意2:链式结构的调用//注意3:between也可以用gtlt//注意4:逻辑删除is_deleted=0List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);
      }
    2. 组装排序条件:
      //按年龄降序查询用户,如果年龄相同则按id升序排列
      //SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,id ASC
      queryWrapper.orderByDesc("age").orderByAsc("id");
    3. 组装删除条件:
      public void test03(){//删除email为空的用户//DELETE FROM t_user WHERE (email IS NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.isNull("email");//条件构造器也可以构建删除语句的条件int result = userMapper.delete(queryWrapper);//注意:如果加上了逻辑删除,那么得到的sql语句是update语句System.out.println("受影响的行数:" + result);
      }
    4. 实现修改功能:
      1. update方法的两种使用方式:

        1. 方式1:User Entity:设置要修改的内容(字段)。Wrapper<User> updateWrapper:查询要修改的记录。
        2. 方式2:User Entity设置为Null。Wrapper<User> updateWrapper:同时设置要修改的内容(字段)、查询要修改的记录。
      2. 案例:
        @Test
        public void test04() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改//UPDATE t_user SET age=?, email=? WHERE (username LIKE ? AND age > ? OR email IS NULL)queryWrapper.like("username", "a").gt("age", 20).or().isNull("email");User user = new User();user.setAge(18);user.setEmail("user@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("受影响的行数:" + result);
        }
    5. 条件的优先级:加入小括号
      @Test
      public void test042() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改//UPDATE t_user SET age=?, email=? WHERE (username LIKE ? AND (age > ? OR email IS NULL))//lambda表达式内的逻辑优先运算//从源码中可以看出:这里的" i(Consumer<Param> consumer 》Wrapper) "其实就是Wraapper(条件构造器)queryWrapper.like("username", "a").and(i -> i.gt("age", 20).or().isNull("email"));User user = new User();user.setAge(18);user.setEmail("user@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("受影响的行数:" + result);
      }
    6. 组装select子句:只查询某些字段
      @Test
      public void test05() {//查询用户信息的username和age字段//SELECT username,age FROM t_userQueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("username", "age");//selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值为nullList<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);
      }
    7. 实现子查询
      @Test
      public void test06() {//查询id小于等于3的用户信息//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (id IN (select id from t_user where id <= 3))QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.inSql("id", "select id from user where id <= 3");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);
      }
  3. UpdateWrapper使用
    1. 修改功能

      @Test
      public void test07() {//将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改//组装set子句以及修改条件UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();//lambda表达式内的逻辑优先运算updateWrapper.set("age", 18).set("email", "user@atguigu.com").like("username", "a").and(i -> i.gt("age", 20).or().isNull("email"));//这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null//UPDATE t_user SET username=?, age=?,email=? WHERE (username LIKE ? AND (age > ? OR email IS NULL))//User user = new User();//user.setName("张三");//int result = userMapper.update(user, updateWrapper);//UPDATE t_user SET age=?,email=? WHERE (username LIKE ? AND (age > ? OR email IS NULL))int result = userMapper.update(null, updateWrapper);System.out.println(result);
      }
  4. 模拟开发中组装条件的情况
    1. 业务:开发过程中肯定是页面各种(DRUD)条件传给后台,后台拼接这些(多个)条件成一条长长的sql语句。
    2. 需求:判断,这些条件是否要拼接到sql语句中(可能页面没有做出选择(如下拉框))。
    3. 案例:
      @Test
      public void test08() {//定义查询条件,有可能为null(用户未输入或未选择(如下拉框、复选框))String username = null;Integer ageBegin = 10;Integer ageEnd = 24;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成if(StringUtils.isNotBlank(username)){queryWrapper.like("username","a");}if(ageBegin != null){queryWrapper.ge("age", ageBegin);}if(ageEnd != null){queryWrapper.le("age", ageEnd);}//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age >=? AND age <= ?)List<User> users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);
      }
  5. 使用condition组装条件的:解决4的麻烦写法
    1. @Test
      public void test08UseCondition() {//定义查询条件,有可能为null(用户未输入或未选择)String username = null;Integer ageBegin = 10;Integer ageEnd = 24;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成queryWrapper .like(StringUtils.isNotBlank(username), "username", "a").ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd);//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age >=? AND age <= ?)List<User> users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);
      }
  6. LambdaQueryWrapper使用:解决字段名容易写错问题
    @Test
    public void test09() {//定义查询条件,有可能为null(用户未输入)String username = "a";Integer ageBegin = 10;Integer ageEnd = 24;LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();//避免使用字符串表示字段,防止运行时错误//函数式接口。 这里通过函数直接访问到实体类属性对应的表字段名。//其中:getName是属性,getAge是属性lambdaQueryWrapper.like(StringUtils.isNotBlank(username), User::getName, username).ge(ageBegin != null, User::getAge, ageBegin).le(ageEnd != null, User::getAge, ageEnd);List<User> users = userMapper.selectList(lambdaQueryWrapper);users.forEach(System.out::println);
    }
  7. LambdaUpdateyWrapper使用:解决字段名容易写错问题
    @Test
    public void test10() {//组装set子句LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();lambdaUpdateWrapper.set(User::getAge, 18).set(User::getEmail, "user@atguigu.com").like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));      //lambda表达式内的逻辑优先运算User user = new User();int result = userMapper.update(user, lambdaUpdateWrapper);System.out.println("受影响的行数:" + result);
    }

5 通用枚举

  1. 业务:在开发中,表中的有些字段值是固定的,例如性别(男或女)。此时我们可以使用(java中)MyBatis-Plus的通用枚举来规定性别的值。
  2. 功能“集合”:通用枚举
  3. “神的”冰箱:mybatis-plus
  4. 演示
    1. 第一步:表,sex int(10),1:男,2:女
    2. 第二步:创建枚举
      @Getter  //  lombok自动生成get方法(不需要设置set方法)
      public enum SexEnum {MALE(1, "男"),                          //  值1FEMALE(2, "女");                        //  值2@EnumValue   //  要把枚举的哪个属性的值插入到数据中,就在这个属性上加上@EnumValue注解private Integer sex;                    //  属性1private String sexName;                 //  属性2SexEnum(Integer sex, String sexName) {  //  构造器this.sex = sex;this.sexName = sexName;}
      }
    3. 第三步:实体类User.java中,使用枚举:private SexEnum sex;表示性别
    4. 第四步:测试添加
      @Test
      public void test(){User user = new User();user.setName("Enum");user.setAge(20);//设置性别信息为枚举项,会将@EnumValue注解所标识的属性值存储到数据库user.setSex(SexEnum.MALE);//INSERT INTO t_user ( username, age, sex ) VALUES ( ?, ?, ? )//Parameters: Enum(String), 20(Integer), 1(Integer)int result = userMapper.insert(user);System.out.println("resutl="+result);
      }
      1. Caused by: java.sql.SQLException: Incorrect integer value: 'MALE' for column 'sex' at row 1。即默认情况下,会尝试把枚举类型的名称(如MALE、FEMALE)插入到表中的sex字段。但sex字段是int类型,不是varchar类型,所以报错。
    5. 第五步:mybatis-plus对枚举的支持
      1. 修改实体类:@EnumValue // 要把枚举的哪个属性的值插入到数据中,就在这个属性上加上@EnumValue注解
      2. application.yml配置扫描通用枚举,让mybatis-plus知道枚举是谁。然后才能够根据@EnumValue注解来解析枚举类型,把枚举中相应属性的值插入数据库中:
        spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://10.203.5.185:3306/fLearn?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=falseusername: rootpassword: MySQL#567890
        mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#配置mybatis类型别名所对应的包#此配置后,默认把类名当做此类型的别名,且不区分大小写(resultType="User"和resultType="user"都是指向User.java类型)type-aliases-package: com.guigu.pojo # 配置扫描通用枚举所在的包type-enums-package: com.guigu.enums
    6. 第六步:再次测试,正确,插入1
      1. ==>  Preparing: INSERT INTO user ( id, name, age, sex ) VALUES ( ?, ?, ?, ? )
        ==> Parameters: 1600180390154993665(Long), Enum(String), 20(Integer), 1(Integer)
        <==    Updates: 1

三 插件

1 分页插件(内置)

  1. 配置类:配置mybatis-plus的插件功能(这里配置的是分页插件功能)

    @Configuration
    @MapperScan("com.guigu.mapper") //可以将启动类中的注解移到此处
    public class MybatisPlusConfig {/**** 1 怎么来配置mybatis-plus中的插件?*   这里所需要的类型是MybatisPlusInterceptor,这是mybatis-plus的一个拦截器,用于配置mybatis-plus中的插件的。* 2 为什么要使用拦截器MybatisPlusInterceptor呢?*    这里边的原理和mybatis分页插件的功能是一样的,工作流程如下 :*   (1)第一步:执行查询功能。*   (2)第二步:拦截器对查询功能进行拦截。*   (3)第三步:拦截器对查询功能的基础上做了额外的处理,达到分页的效果(功能)。* 3 对比配置mybatis中的插件*   用的也是拦截器的方式,如配置mybatis分页插件。** @return MybatisPlusInterceptor*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//参数:要配置的具体插件:new PaginationInnerInterceptor(DbType.MYSQL)是专门为mysql定制实现的内部的分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
    }
  2. 测试类:使用mybatis-plus的插件功能
    @Test
    public void testPage(){  //设置分页参数:页码、显示的条数Page<User> page = new Page<>(2, 3);
        //第1个参数:分页对象//第2个参数:条件构造器,如果设置为null,即查询所有//返回值就是一个Page对象,即返回上面所new出来的page对象,数据都在其中//对应的sql语句:SELECT id,name,age,email FROM user LIMIT ?userMapper.selectPage(page, null); //获取当前页数据List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("当前页:"+page.getCurrent());System.out.println("每页显示的条数:"+page.getSize());System.out.println("总记录数:"+page.getTotal());System.out.println("总页数:"+page.getPages());System.out.println("是否有上一页:"+page.hasPrevious());System.out.println("是否有下一页:"+page.hasNext());
    }

2 xml自定义分页

  1. 应用场景

    1. 我们自定义查询数据库表的sql语句,这种情况下如何使用mybatis-plus提供的分页插件来实现分页功能呢?
  2. 案例:根据年龄查询用户信息,并且分页
    1. 第一步:创建Mapper接口方法:模仿mybatis-plus内置的分页插件的方法,如selectPage()方法。

      @Repository
      public interface UserMapper extends BaseMapper<User> {/*** 需求:根据年龄查询用户列表,分页显示** 第一步:xml自定义分页,Mapper接口方法*       第1步:如果想要mybatis-plus的分页插件来作用于我们自定义的sql语句的话,第一个参数必须得是一个分页对象:Page<User> page。* 第二步:因为Mapper接口方法有2个参数的话*       方案1:使用mybatis提供的访问方式*       方案2:也可以使用@param来设置命名参数,来规定参数的访问规则** @param page mybatis-plus提供的分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位。虽然在自定义的sql语句中不会用到Page<User> page,但是如果想在自定义的sql语句中使用mybatis-plus的分页插件使用分页功能,那么第一个参数必须得是Page。* @param age 年龄* @return Page<User>*/Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
      }
    2. 第二步:映射文件XxxMapper.xml
      <?xml version ="1.0" encoding="UTF-8" ?>
      <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
      <mapper namespace ="com.guigu.mapper.UserMapper" ><!--SQL片段,记录基础字段--><sql id="BaseColumns">id,username,age,email</sql><!--IPage<User> selectPageVo(Page<User> page, Integer age);--><!-- 因为现在仍然使用的是mybatis-plus提供的分页插件来实现分页功能,所以这里我们只编写查询的sql语句(没有limit),而分页功能的实现还是交给mybatis-plus的分页插件--><!-- resultType="User"中的”User“是类型别名,因为之前我们没有设置类型别名”User“(更不是mybatis内置类型别名),所以我们要在配置文件application.yml中设置mybatis类型别名”User“,之后,我们就可以通过类型别名”User“访问到User.java类型了。--><select id="selectPageVo" resultType="User">SELECT <include refid="BaseColumns"></include> FROM t_user WHERE age > # {age}</select>
      </mapper>
    3. 第三步:在application.yml中设置User.java的类型别名User,以供映射文件中使用
      spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://10.203.5.185:3306/fLearn?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=falseusername: rootpassword: MySQL#567890
      mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#配置mybatis类型别名所对应的包#此配置后,默认把类名当做此类型的别名,且不区分大小写(resultType="User"和resultType="user"都是指向User.java类型)type-aliases-package: com.guigu.pojo
    4. 第四步:测试
      @Test
      public void testSelectPageVo(){//设置分页参数Page<User> page = new Page<>(1, 5);//sql语句:SELECT id,name,age,email FROM user WHERE age > ? LIMIT ?userMapper.selectPageVo(page, 20);//获取分页数据List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("当前页:"+page.getCurrent());System.out.println("每页显示的条数:"+page.getSize());System.out.println("总记录数:"+page.getTotal());System.out.println("总页数:"+page.getPages());System.out.println("是否有上一页:"+page.hasPrevious());System.out.println("是否有下一页:"+page.hasNext());
      }

3 乐观锁插件

  1. 乐观锁和悲观锁

    1. 悲观锁:小李操作时,小王一直处于阻塞状态。直到小李操作完成,并放开锁。小王拿到此释放锁,能才操作。
    2. 乐观锁:
      1. 乐观锁一般的实现:一般通过在数据库表中设置版本号字段(versions)来实现的。
      2. 乐观锁实现流程:
        1. 第1步:数据库中添加version字段
        2. 第2步:取出记录时,获取当前version:SELECT id,`name`,price,`version` FROM product WHERE id=1
        3. 第3步:更新时,version + 1,如果where语句中的version版本不对,则更新失败:UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1
  2. 模拟修改冲突
    1. 第一步:创建表
      1. version int(11) default 0 comment '乐观锁版本号'
    2. 第二步:添加测试数据
    3. 第三步:创建实体类
    4. 第四步:添加Mapper接口

      public interface ProductMapper extends BaseMapper<Product> {
      }

    5. 第五步:测试

      @SpringBootTest
      public class LeguanTest {@Autowiredprivate ProductMapper productMapper;@Testpublic void testConcurrentUpdate() {//0、商品成本价80//1、小李获取:当前价格Product p1 = productMapper.selectById(1L);System.out.println("小李取出的价格:" + p1.getPrice());//2、小王获取:当前价格Product p2 = productMapper.selectById(1L);System.out.println("小王取出的价格:" + p2.getPrice());//3、小李修改:将价格加了50元,存入了数据库p1.setPrice(p1.getPrice() + 50);int result1 = productMapper.updateById(p1);System.out.println("小李修改结果:" + result1);//4、小王修改:将商品减了30元,存入了数据库p2.setPrice(p2.getPrice() - 30);int result2 = productMapper.updateById(p2);System.out.println("小王修改结果:" + result2);//5、老板查询最后的结果:价格覆盖,最后的结果:70(小于成本价,亏)Product p3 = productMapper.selectById(1L);System.out.println("老板查询最后的结果:" + p3.getPrice());}
      }

  3. mybatis-plus提供的乐观锁插件实现乐观锁控制的功能
    1. 第一步:修改实体类,添加@version,标识:数据库表中,使用哪个字段做为乐观锁版本号字段(这里是version)

      @Data
      @TableName("t_product")
      public class Product {private Long id;private String name;private Integer price;@Version //标识:数据库表中,哪个字段做为乐观锁版本号字段(这里是version)private Integer version;
      }
    2. 第二步:添加乐观锁插件配置
      1. 需求

        1. 类比“分页插件”:前面使用mybatis-plus分页插件的时候,要对分页插件进行指定、配置(如使用mysql 或 oracle的分页功能)。
        2. 因为使用mybatis-plus分页插件的时候,也要指定、配置乐观锁分页插件。
      2. 配置类中:指定、配置乐观锁插件
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor(){
               MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
               //添加乐观锁插件
               interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
               return interceptor;
        }
    3. 第三步:重新测试,正确,是150,因为版本号不匹配,所以小王修改不成功。
      1. UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    4. 第四步:优化流程,保证小王的修改也要可执行

      @SpringBootTest
      public class LeguanTest {@Autowiredprivate ProductMapper productMapper;@Testpublic void testConcurrentUpdate() {//第1步:小李获获取:当前的价格,100Product p1 = productMapper.selectById(1L);//第2步:小王获获取:当前的价格,100Product p2 = productMapper.selectById(1L);//第3步:小李修改 + 50p1.setPrice(p1.getPrice() + 50);int result1 = productMapper.updateById(p1);System.out.println("小李修改的结果:" + result1);//第4步:小王修改 - 30p2.setPrice(p2.getPrice() - 30);int result2 = productMapper.updateById(p2);System.out.println("小王修改的结果:" + result2);if(result2 == 0){//第5步:操作失败,重试:重新获取version并更新p2 = productMapper.selectById(1L);p2.setPrice(p2.getPrice() - 30);result2 = productMapper.updateById(p2);}System.out.println("小王修改重试的结果:" + result2);//第6步:老板看价格,120,满意Product p3 = productMapper.selectById(1L);System.out.println("老板看价格:" + p3.getPrice());}
      }

四 mybatisX插件(idea快速开发插件)

  1. 业务:真正开发过程中,MyBatis-Plus并不能为我们解决所有问题,例如一些复杂的SQL、多表联查,我们就需要自己去编写代码和SQL语句,我们该如何快速的解决这个问题呢?
  2. 需求:快速开发
  3. 功能“集合”:mybatisX插件
  4. “神的”冰箱:基于idea的快速开发插件
  5. 操作步骤
    1. 准备:idea 》settings 》Plugins 》搜索mybatisX 》Install 》重启idea
    2. 使用1:快速对应Mapper接口、映射文件
      1. 业务:真正开发过程中,因为1个Mapper接口 + 1个映射文件对应的是一张表,而数据库中肯定会有很多表,所以会有非常多的Mapper接口、映射文件。
      2. 需求:快速在众多的映射文件中,找到当前Mapper接口对应的那一个映射文件,反之亦然
      3. 功能“集合”:快速地定位当前Mapper接口的对应的映射文件,反之亦然
      4. “神的”冰箱:mybatisX插件
      5. 案例
        1. 第1步:Mapper接口的小鸟
        2. 第2步:映射文件的小鸟
    3. 使用2:mybatisX插件代码生成器功能(实体类、mapper接口、映射文件、Service接口及实现其类)
      1. 第1步:springboot工程,清理工程,
      2. 第2步:pom.xml
        1. spring-boot-starter、spring-boot-starter-test、mybatis-plus-boot-starter、lombok、mysql-connector-java
      3. 第3步:application.yml
        spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=falseusername: rootpassword: root
        # 配置MyBatis日志
        mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      4. 第4步:mybatisX插件代码生成器,快速生成相对应的代码
        1. 第a步:使用idea的DataBase数据库模块连接到数据库,并测试连接,下载驱动,再测试连接
        2. 第b步:idea的DataBase数据库模块 》schemas 》选择数据库mybatis 》选择数据表user 》右击 》Mybatisx-Generator 》输入内容1:
          1. module path:选择工程(代码会直接生成到工程中)
          2. base package:基础包。修改成自己的包。所有的内容(代码、配置文件等)都会生成到这个包下面。
          3. encoding:编码。utf-8。
          4. superClass:父类,咱们没有的话可以不加
          5. base path:默认是主程序目录src/main/java。生成的内容所在的路径。
          6. ignore field prefix:忽略字段的前缀。比如,表字段(a_id、a_username),忽略字段的前缀,实体类发展(id、username)。
          7. ignore table prefix:忽略表的前缀。比如,表t_user,忽略表的前缀后,实体类User.java。
          8. relative package:修改成pojo。生成的实体类到的包。
          9. ignore field suffix:忽略字段的后缀。
          10. ignore table prefix:忽略表的后缀。
        3. 第c步:next 》输入内容2 》配置生成的Service、Mapper接口、映射文件:
          1. annotation:选择注解。Mybatis-plus 3。因为mybatisx是属于mybatis-plus中的一个插件,所以选择Mybatis-plus 3。
          2. options:代码生成器生成的各个组件的选项
            1. Comment:注释
            2. toString/hashCode/equals:实体类的对应方法。不需要,因为可以直接选择lombok
            3. lombok:@Data
          3. template:代码生成器生成代码的模板,选择Mybatis-plus 3
          4. 方框:各个组件生成的位置
            1. mapperInterface:mapper接口放在哪?
            2. mapperXml:映射文件放在哪?
            3. serviceImpl:service接口实现类放在哪?
            4. serviceInterface:service接口放在哪?
        4. 第d步:查看效果
    4. 使用3:mybatisx快速生成crud
      1. 需求:在XxxMapper接口中实现自定义的crud功能
      2. 案例1:添加方法insert。不需要写返回值,只需要写方法名即可,mybatisx可以根据方法名快速地帮我们写出相对应的sql语句
        1. 第1步:来到XxxMapper接口类内
        2. 第2步:敲insert(方法名要做到,见名识意)
          1. 下面带小鸟图标的,就是mybatisx给我们提供的模板

            1. 选择:insertSelective。在我们学习mybatis逆向工程的时候就有这个方法。如果,向添加方法中传输的实体类对象的某个属性的值为null,那么此属性对应的字段是不会出现在Sql语句中的。
            2. alt + anter
            3. 选择:[MybatisX] Generate Mybatis Sql
            4. 效果:
              1. XxxMapper接口类的方法自动补全:int insertSelective(User user);
              2. XxxMapper.xml自动补全sql语句。小鸟图标跳过去。
        3. 注意:
          1. 当我们在XxxMapper接口中创建了一个自定义方法之后,mybatisx会把此方法跟映射文件中的sql进行关联。如果,此方法在映射文件中没有找到相对应的sql语句的话,就会报编译错(下划红色波浪线)。
      3. 案例2:查询方法select
        1. select(mybatisx带出来,可选)+ And(mybatisx带出来,可选) + By(mybatisx带出来,添加可选的查询条件)+ Between(mybatisx带出来,条件成立的时候)
        2. OrderBy(mybatisx带出来,添加可选的排序方式)
      4. 案例3:修改方法update
        1. 敲update(mybatisx带出来,可选)+ And(mybatisx带出来,可选) + By(mybatisx带出来,添加可选的条件)
      5. 案例4:添加方法delete
        1. 根据单个字段删除:敲delete(mybatisx带出来,可选)
        2. 根据多个字段删除:敲deleteById + And(mybatisx带出来,可选)

五 多数据源

  1. 业务:多个数据库、读写分离、一主多从、混合模式等
  2. 需求:多数据源
  3. 功能“集合”:多数据源
  4. “神的”冰箱:mybatis-plus
  5. 案例
    1. 第一步:数据库、表

      1. 第1步:mybatis-plus库,user表
      2. 第2步:mybatis-plus-1库,product表
    2. 第二步:mybatis-plus设置多数据源
      1. 第1步:pom.xml,依赖

        1. dynamic-datasource-spring-boot-starter:多数据源所需要的依赖。
      2. 第2步:application.yml,配置多数据源
        spring:# 配置数据源信息datasource:dynamic:# 设置默认的数据源或者说主数据源,默认值即为masterprimary: master# 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false未匹配到指定数据源时使用默认数据源strict: falsedatasource:master:url: jdbc:mysql://localhost:3306/fLearn?characterEncoding=utf-8&useSSL=falsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: MySQL#567890#从数据源slave_1:url: jdbc:mysql://localhost:3306/fLearn2?characterEncoding=utf-8&useSSL=falsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: MySQL#567890
      3. 第3步:编码
        1. 第a步:User.java、UserService接口,UserServiceImpl实现类,实现类中指定所操作的数据源

          public interface UserService extends IService<User> {
          }
          @DS("master") //指定所操作的数据源
          @Service
          public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
          }
        2. 第b步:Product.java、ProductService接口,ProductServiceImpl实现类,实现类中指定所操作的数据源
          public interface ProductService extends IService<Product> {
          }

          @DS("slave_1")//指定所操作的数据源
          @Service
          public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
          implements ProductService {
          }

        3. 第c步:启动类,@MapperScan扫描XxxMapper接口
    3. 第三步:测试,从两个数据库中都可以读取得到数据
      @Autowired
      private UserService userService;
      @Autowired
      private ProductService productService;
      @Test
      public void testDynamicDataSource(){
         System.out.println(userService.getById(1L));
         System.out.println(productService.getById(1L));
      }
    4. 注意事项
      1. @DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。

六 代码生成器(内置)

  1. mybatis逆向工程

    1. 概述

      1. mybatis逆向工程也是代码生成器,但是跟mybatis-plus代码生成器是有区别的。
    2. 原理
      1. 根据表,逆向生成实体类、mapper接口、映射文件。
    3. 自动生成
      1. 实体类
      2. mapper接口
      3. 映射文件
  2. mybatis-plus代码生成器
    1. 概述
    2. 原理
      1. 根据表,逆向生成(更多)控制层、业务层、mapper接口、映射文件、实体类。
    3. 自动生成(各个组件)
      1. 控制层
      2. 业务层
      3. mapper接口
      4. 映射文件
      5. 实体类
    4. 注意事项
      1. 不需要刨根问底,没意义。
      2. 只需要通过老师给的模板(老师也是从官网下复制下来的)生成相对应的代码即可。
  3. 操作步骤:
    1. 第一步:依赖

      1. mybatis-plus-generator:mybatis-plus代码生成器的核心依赖。
      2. freemarker:因为在我们当前实现的功能中,它会生成freemarker引擎模板,所以说需要freemarker相关依赖。
    2. 第二步:测试类,直接执行即可
      public class FastAutoGeneratorTest {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://10.203.5.185:3306/fLearn?characterEncoding=utf-8&userSSL=false", "root", "MySQL#567890")//  全局配置.globalConfig(builder -> {builder.author("atguigu") // 设置作者//.enableSwagger() // 开启 swagger 模式.fileOverride() // 覆盖已生成文件(代码重新且覆盖生成).outputDir("D://mybatis_plus"); // 指定输出目录})//   包设置//   如下图所示,所有的代码都会生成到com.atguigu.mybatisplus包下。.packageConfig(builder -> {builder.parent("com.atguigu") // 设置父包名.moduleName("mybatisplus") // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus"));// 设置映射文件XxxMapper.Xml的生成路径})//    策略配置.strategyConfig(builder -> {builder.addInclude("t_user") // 设置需要逆向生成的表的表名.addTablePrefix("t_", "c_"); // 设置过滤表前缀}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
      }
    3. 第三步:验证:直接执行main方法。
      1. 非常快,只花费9毫秒
      2. 生成完成后,自动打开代码生成目录

mybatis-plus,sgg,杨bochao相关推荐

  1. 使用Python制作数据动画

    The goal of this guide is to show you how to update a graph in real-time. This can be used for a var ...

  2. 10期16年3月博客期刊

    一. hibernate与mybatis的比较- 杨士超 自荐理由:现在编程中轻量级框架越来越受欢迎,因此不管是简单可靠易上手的mybatis还是使用灵活的hibernate都是我们的必修课:所以本篇 ...

  3. mybatis自动建表oracle,利用mybatis-generator自动生成代码 - 菩提树下的杨过 - 博客园...

    mybatis-generator 有三种用法:命令行.eclipse插件.maven插件.个人觉得maven插件最方便,可以在eclipse/intellij idea等ide上可以通用. 下面是从 ...

  4. mybatis plus 插入生成id_springcloud微服务快速教程之分布式ID解决方案(mybatisplus篇)...

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 作者 |  大叔杨 来源 |  urlify.cn/BfIn2m 前言 分布式系统中,分布式ID是个必须解决的问题点: ...

  5. Mybatis 一对多 结果集映射 简单入门 易懂

    Mybatis官方文档说明处 Mybatis 一对多 结果集映射 简单入门 易懂 一.搭建数据库环境 二.idea 搭建maven 项目 (mybatis-demo) 2.1.项目结构 2.2.导入依 ...

  6. boot mybatis mysql_SpringBoot+Mybatis+MySql学习

    介绍一下SpringBoot整合mybatis,数据库选用的是mysql. 首先创建数据库 CREATE DATABASE test; 建表以及插入初始数据(sql是从navicat中导出的) SET ...

  7. spring和mybatis整合:使用xml方式

    文章目录 spring和mybatis整合:使用xml方式 1. 创建数据库 2. 创建工程,pom.xml文件如下: 3. 依赖下载地址如下: 4. 配置mybatis的全局配置,在resource ...

  8. 专访杨开振:程序员除了敲代码还能做什么?

    杨开振<深入浅出Spring Boot 2.x>作者 当前互联网后端开发中Java EE占据了主导地位.对于Java EE开发,首选框架和事实标准是Spring框架.在传统的Spring开 ...

  9. mybatis学习教程(二)初级的增、删、查、改

    引言 本文主要从一个基础实例,讲解Mybatis的实现,已经每一步的详细讲解.我会将项目共享在百度云盘,文章最后! 1.项目结构 2.项目配置  2.1 配置SqlMapConfig.xml 根据My ...

最新文章

  1. Day25 linux shell中的特殊符号与命令
  2. latex 下划线_备战美赛!论文写作必备Latex排版教程之单词间隔、标题及交叉引用...
  3. mysql极客_极客mysql16
  4. (数据库系统概论|王珊)第三章关系数据库标准语言SQL:习题
  5. 1381. 设计一个支持增量操作的栈
  6. 解决Vue报错:Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location
  7. c++ int最大值_PTA「实验7-1-10 交换最小值和最大值」
  8. Apache 别名与重定向
  9. c++调用栈库函数_大华 | C/C++ 校招笔试题
  10. 网络知识 -- 第二部
  11. 商业计划书范文3000_凤城编写商业计划书范文模板格式
  12. linux查看网卡带宽命令,Linux查看网卡带宽的两个命令
  13. 手机qq下载文件地址
  14. PayPal社交游戏及移动娱乐产业的海外商机
  15. html5源码 母亲节,母亲节H5:非常有创意的5款母亲节H5案例分享
  16. java 龟兔赛跑_Java实现多线程模拟龟兔赛跑
  17. VAF,MAF,肿瘤纯度,MCF,CCF的概念和计算方法 (转载)
  18. 看脸的世界:牙齿整齐找工作更容易
  19. Linux安装RabbitMQ详细教程
  20. 浅析微服务架构应该在什么时候采用

热门文章

  1. ubuntu系统中webpy的使用
  2. 如何设计出优秀的EDM邮件营销模板
  3. java语言实现吃水果问题_Java 面向对象 之 人吃水果
  4. 上海市土木工程人才需求暴涨
  5. RabbitMQ 四种类型发送接收数据方式
  6. NOIP模拟 葫芦(分数规划)
  7. 梦想经不起等待 -- 美文转载
  8. 新底座、新产品、新方案,2022用友BIP技术大会三大数智化突破
  9. 抖音如何快速涨粉?李佳琦涨粉技巧揭秘
  10. 利用node爬取王者荣耀英雄信息,并存入数据库