MyBatisPlus配置与实现

目录

基于SpringBoot使用MyBatisPlus

标准数据层开发

Lombok

分页功能

DQL编程控制

构建条件查询

null判定

查询投影

聚合查询

分组查询

查询条件

模糊查询

排序查询

映射匹配兼容性

DML编程控制

id生成策略控制

雪花算法:

简化配置

多记录操作

逻辑删除​编辑

乐观锁

快速开发


 

        MybatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提供效率

MyBatisPlus的官网为:https://mp.baomidou.com/

基于SpringBoot使用MyBatisPlus

        由于MP并未被收录到idea的系统内置配置,无法直接选择加入,需要手动在pom.xml中配置添加pom.xml补全依赖

 

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
<!--        druid数据源可以加也可以不加,SpringBoot有内置的数据源,可以配置成使用Druid数据源-->


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>

        从MP的依赖关系可以看出,通过依赖传递已经将MyBatis与MyBatis整合Spring的jar包导入,我们不需要额外在添加MyBatis的相关jar包

 添加MP的相关配置信息

根据数据库表创建实体类

创建Dao接口

@Mapper
public interface UserDao extends BaseMapper<User> {
}

Dao接口要想被容器扫描到,有两种解决方案:

  • 方案一:在Dao接口上添加@Mapper注解,并且确保Dao处在引导类所在包或其子包中
  • 该方案的缺点是需要在每一Dao接口中添加注解
  • 方案二:在引导类上添加@MapperScan注解,其属性为所要扫描的Dao所在包
  • 该方案的好处是只需要写一次,则指定包下的所有Dao接口都能被扫描到,@Mapper就可以不写


标准数据层开发

        数据层标准的CRUD(增删改查)的实现与分页功能

Lombok

Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <!--
    <version>1.18.12</version>
    版本可以不用写,因为SpringBoot中已经管理了lombok的版本。
    -->
</dependency>

 安装Lombok的插件

新版本IDEA已经内置了该插件,如果删除setter和getter方法程序有报红,则需要安装插件

 可以访问如下网站 https://plugins.jetbrains.com/plugin/6317-lombok/versions

 Lombok常见的注解有:

  • @Setter:为模型类的属性提供setter方法
  • @Getter:为模型类的属性提供getter方法
  • @ToString:为模型类的属性提供toString方法
  • @EqualsAndHashCode:为模型类的属性提供equals和hashcode方法
  • @Data:是个组合注解,包含上面的注解的功能
  • @NoArgsConstructor:提供一个无参构造函数
  • @AllArgsConstructor:提供一个包含所有参数的构造函数
@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
}

分页功能

IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper)
  • IPage:用来构建分页查询条件
  • Wrapper:用来构建条件查询的条件,目前我们没有可直接传为Null
  • IPage:返回值,你会发现构建分页条件和方法的返回值都是IPage

        IPage是一个接口,我们需要找到它的实现类来构建它,具体的实现类,可以进入到IPage类中按ctrl+h,会找到其有一个实现类为Page

调用方法传入参数获取返回值

@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {

    @Autowired
    private UserDao userDao;
    

@Test
    void testGetByPage(){
        //IPage对象封装了分页操作相关的数据
        IPage page  = new Page(2,3);
        userDao.selectPage(page,null);
        System.out.println("当前页码值:"+page.getCurrent());
        System.out.println("每页显示数:"+page.getSize());
        System.out.println("一共多少页:"+page.getPages());
        System.out.println("一共多少条数据:"+page.getTotal());
        System.out.println("数据:"+page.getRecords());
    }

}

 设置分页拦截器

@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mpInterceptor(){
        //1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        //2.添加具体的拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mpInterceptor;
    }
}

这些内容在MP的官方文档中有详细的说明,我们可以查看官方文档类配置


 

 

 修改application.yml配置文件,查询日志

# 开启mp的日志(输出到控制台)
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

DQL编程控制

        MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合。

 Wrapper类是用来构建查询条件的

构建条件查询

因为它是一个接口,所以我们需要去找它对应的实现类

    @Test
    void testGetAll() {
        //方式一:按条件查询
        QueryWrapper qw = new QueryWrapper();
        qw.lt("age",18);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);

        //方式二:lambda格式按条件查询
        QueryWrapper<User> qw = new QueryWrapper<User>();
        qw.lambda().lt(User::getAge, 10);
        List<User> userList = userDao.selectList(qw);
        System.out.println(userList);

        //方式三:lambda格式按条件查询
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.lt(User::getAge, 10);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);


        //并且与或者关系
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //并且关系:10到30岁之间
        lqw.lt(User::getAge, 30).gt(User::getAge, 10);
        //或者关系:小于10岁或者大于30岁
        lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

}

null判定

        因为前端没有输入值2,所以如果不处理的话,就会出现 price>8000 and price < null问题

使用一个age属性,如何去接收页面上的两个值

方案一:添加属性age2,这种做法可以但是会影响到原模型类的属性内容

@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
}

方案二:新建一个模型类,让其继承User类,并在其中添加age2属性,UserQuery在拥有User属性后同时添加了age2属性。

@Data
public class UserQuery extends User {
    private Integer age2;
}
@SpringBootTest
class Mybatisplus02DqlApplicationTests {

        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //先判定第一个参数是否为true,如果为true连接当前条件
        lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2());
        lqw.gt(null != uq.getAge(),User::getAge, uq.getAge());
        lqw.lt(null != uq.getAge2(),User::getAge, uq.getAge2())
           .gt(null != uq.getAge(),User::getAge, uq.getAge());
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

}

查询投影

select(...)方法用来设置查询的字段列,可以设置多个,最终的sql语句为:

//        查询投影
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        lqw.select(User::getId,User::getName,User::getAge);
        QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("id","name","age","tel");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

最终的sql语句为:SELECT id,name,age,tel FROM user 

聚合查询

  • count:总记录数
  • max:最大值
  • min:最小值
  • avg:平均值
  • sum:求和
        QueryWrapper<User> lqw = new QueryWrapper<User>();

        lqw.select("count(*) as count, tel");
        //SELECT count(*) as count FROM user

        lqw.select("max(age) as maxAge");
        //SELECT max(age) as maxAge FROM user

        lqw.select("min(age) as minAge");
        //SELECT min(age) as minAge FROM user

        lqw.select("sum(age) as sumAge");
        //SELECT sum(age) as sumAge FROM user

        lqw.select("avg(age) as avgAge");
        //SELECT avg(age) as avgAge FROM user
        
        
        lqw.groupBy("tel");
        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);

分组查询

        QueryWrapper<User> lqw = new QueryWrapper<User>();
        lqw.select("count(*) as count, tel");
        lqw.groupBy("tel");
        List<Map<String, Object>> userList = userDao.selectMaps(lqw);
        System.out.println(userList);

SELECT count(*) as count,tel FROM user GROUP BY tel

聚合与分组查询,无法使用lambda表达式来完成

查询条件

  • 范围匹配(> 、 = 、between)
  • 模糊匹配(like)
  • 空判定(null)
  • 包含性匹配(in)
  • 分组(group)
  • 排序(order)
        //条件查询
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //等同于=
        lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry");
        User loginUser = userDao.selectOne(lqw);
        System.out.println(loginUser);

        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
        //范围查询 lt le gt ge eq between
        lqw.between(User::getAge,10,30);
        SELECT id,name,password,age,tel FROM user WHERE (age BETWEEN ? AND?)
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

SELECT id,name,password,age,tel FROM user WHERE (name = ? AND password = ?)

模糊查询

  • like():前后加百分号,如 %J%
  • likeLeft():前面加百分号,如 %J
  • likeRight():后面加百分号,如 J%
        //模糊匹配 like
        lqw.likeLeft(User::getName,"J");
        List<User> userList = userDao.selectList(lqw);
        System.out.println(userList);

排序查询

@Test
void testGetAll(){
        LambdaQueryWrapper<User> lwq = new LambdaQueryWrapper<>();

    /**
    * condition :条件,返回boolean,
        当condition为true,进行排序,如果为false,则不排序
    * isAsc:是否为升序,true为升序,false为降序
    * columns:需要操作的列
    */

        lwq.orderBy(true,false, User::getId);
        userDao.selectList(lw
}

 

  • orderBy排序

        condition:条件,true则添加排序,false则不添加排序
        isAsc:是否为升序,true升序,false降序
        columns:排序字段,可以有多个

  • orderByAsc/Desc(单个column):按照指定字段进行升序/降序
  • orderByAsc/Desc(多个column):按照多个字段进行升序/降序
  • orderByAsc/Desc

        condition:条件,true添加排序,false不添加排序
        多个columns:按照多个字段进行排序
 

具体参考官方文档的条件构造器来学习使用,具体的网址为:
https://mp.baomidou.com/guide/wrapper.html#abstractwrapper


映射匹配兼容性

@Data
@TableName("tbl_user")
public class User {
    private Long id;
    private String name;
    @TableField(value = "pwd",select = false)
    private String password;
    private Integer age;
    private String tel;
    @TableField(exist = false)
    private Integer online;
}
名称@TableField
类型属性注解
位置模型类属性定义上方
作用设置当前属性对应的数据库表中的字段关系
相关属
value(默认):设置数据库表字段名称
exist:设置属性在数据库表字段中是否存在,默认为true,此属性不能与value合并
使用
select:设置属性是否参与查询,此属性与select()映射配置不冲突
名称@TableName
类型类注解
位置模型类定义上方
作用设置当前类对应于数据库表关系
相关属性value(默认):设置数据库表名称

DML编程控制

id生成策略控制

名称@TableId
类型属性注解
位置模型类中用于表示主键的属性定义上方
作用设置当前类中主键属性的生成策略
相关属性value(默认):设置数据库表主键名称
type:设置主键属性的生成策略,值查照IdType的枚举值
@Data
@TableName("tbl_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    @TableField(value = "pwd",select = false)
    private String password;
    private Integer age;
    private String tel;
    @TableField(exist = false)
    private Integer online;
}

  • NONE: 不设置id生成策略
  • INPUT:用户手工输入id
  • ASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型)
  • ASSIGN_UUID:以UUID生成算法作为id生成策略
  • 其他的几个策略均已过时,都将被ASSIGN_ID和ASSIGN_UUID代替掉。

雪花算法:

(SnowFlake),是Twitter官方给出的算法实现 是用Scala写的。其生成的结果是一个64bit大小整数

        1. 1bit,不用,因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0。
        2. 41bit-时间戳,用来记录时间戳,毫秒级
        3. 10bit-工作机器id,用来记录工作机器id,其中高位5bit是数据中心ID其取值范围0-31,低位5bit是工作节点ID其取值范围0-31,两个组合起来最多可以容纳1024个节点
        4. 序列号占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以生产4096个ID

简化配置

 

# mp日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: false
    db-config:
      id-type: assign_id
      table-prefix: tbl_

多记录操作

    void testDelete(){
        //删除指定多条数据
//        List<Long> list = new ArrayList<>();
//        list.add(1402551342481838081L);
//        list.add(1402553134049501186L);
//        list.add(1402553619611430913L);
          userDao.deleteBatchIds(list);
        //查询指定多条数据
//        List<Long> list = new ArrayList<>();
//        list.add(1L);
//        list.add(3L);
//        list.add(4L);
          userDao.selectBatchIds(list);

}

逻辑删除

 

 

        为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,数据保留在数据库中,执行的是update操作

 

@Data
public class User {
    private Long id;
    private String name;
    @TableField(value = "pwd",select = false)
    private String password;
    private Integer age;
    private String tel;
    @TableField(exist = false)
    private Integer online;

    //逻辑删除字段,标记当前记录是否被删除
    @TableLogic(value = "0" ,delval = "1")

    private Integer deleted;

}
    void testDelete(){

        userDao.deleteById(2L);

    }

 

# mp日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: false
    db-config:
      id-type: assign_id
      table-prefix: tbl_
      # 逻辑删除字段名
      logic-delete-field: deleted
      # 逻辑删除字面值:未删除为0
      logic-not-delete-value: 0
      # 逻辑删除字面值:删除为1
      logic-delete-value: 1

逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段

UPDATE tbl_user SET deleted=1 where id = ? AND deleted=0

 

名称@TableLogic
类型属性注解
位置模型类中用于表示删除字段的属性定义上方
作用标识该字段为进行逻辑删除的字段
相关属性value:逻辑未删除值
delval:逻辑删除值

乐观锁

乐观锁主要解决的问题是当要更新一条记录的时候,希望这条记录没有被别人更新。

2000个请求以下解决方案,小型网站

@Data
//设置表名映射关系
//@TableName("tbl_user")
public class User {
    //设置主键生成策略
//    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    @TableField(value = "pwd",select = false)
    private String password;
    private Integer age;
    private String tel;
    @TableField(exist = false)
    private Integer online;
    //逻辑删除字段,标记当前记录是否被删除
//    @TableLogic(value = "0" ,delval = "1")
    private Integer deleted;

    @Version
    private Integer version;

}

添加乐观锁的拦截器
 

@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mpInterceptor() {
        //1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        //2.添加具体的拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        //3.添加乐观锁拦截器
        mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mpInterceptor;
    }
}

修改需要携带version数据 

 MP会将1进行加1,然后,更新回到数据库表中。

多个人修改同一个数据

 参考官方文档来实现:

乐观锁插件 | MyBatis-Plus

快速开发

package com.itheima;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;

public class CodeGenerator {
    public static void main(String[] args) {
        //1.获取代码生成器的对象
        AutoGenerator autoGenerator = new AutoGenerator();

        //设置数据库相关配置
        DataSourceConfig dataSource = new DataSourceConfig();
        dataSource.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        autoGenerator.setDataSource(dataSource);

        //设置全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(System.getProperty("user.dir")+"/mybatisplus_04_generator/src/main/java");    //设置代码生成位置
        globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录
        globalConfig.setAuthor("黑马程序员");    //设置作者
        globalConfig.setFileOverride(true);     //设置是否覆盖原始生成的文件
        globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称
        globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略
        autoGenerator.setGlobalConfig(globalConfig);

        //设置包名相关配置
        PackageConfig packageInfo = new PackageConfig();
        packageInfo.setParent("com.aaa");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
        packageInfo.setEntity("domain");    //设置实体类包名
        packageInfo.setMapper("dao");   //设置数据层包名
        autoGenerator.setPackageInfo(packageInfo);

        //策略设置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("tbl_user");  //设置当前参与生成的表名,参数为可变参数
        strategyConfig.setTablePrefix("tbl_");  //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
        strategyConfig.setRestControllerStyle(true);    //设置是否启用Rest风格
        strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名
        strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名
        strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok
        autoGenerator.setStrategy(strategyConfig);
        //2.执行生成操作
        autoGenerator.execute();
    }
}

代码生成器(新) | MyBatis-Plus

官方文档中获取代码进行修改
 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值