MyBatis-Plus剩余内容

本篇的主要代码依赖于之前的通用Mapper和通用Service篇

前两个星期忙着转正的事情,比较忙。所以快两个周每太更新博客,这周末抓紧时间把剩余的MP的补完,在这里记录一下。


文章目录

  • MyBatis-Plus剩余内容
  • 一、常用注解
    • 1.1 @TableName
    • 1.2 @TableId
    • 1.3 @TableField
    • 1.4 @TableLogic
  • 二、条件构造器Wrapper
    • 2.1 QueryWrapper
      • 2.1.1 组装查询条件selectCount
      • 2.1.2 组装查询条件selectList
      • 2.1.3 组装查询参数selectMaps
      • 2.1.4 组装查询selectOne
      • 2.1.5 调整条件优先级
      • 2.1.6 实现子查询inSql
    • 2.2 UpdateWrapper
      • 2.2.1 组装修改条件update
  • 三、MyBatis-Plus分页插件
    • 3.1 实现步骤
      • :one:添加配置类
      • :two: 测试
  • 四、通用枚举
    • 4.1 数据库表添加字段sex
    • 4.2 配置扫描通用枚举
    • 4.3 新建枚举类
      • 4.3.1 @EnumValue注解
    • 4.4 测试

提示:以下是本篇文章正文内容,下面案例可供参考

一、常用注解

在我们平时的日常开发中,会经常遇到我们的数据小伙伴们在数据库中所创建的 表名要与我们Java开发人员所建的domian层的类名有一个对应关系,这往往在不同的公司都有着不同的要求。

打个比方:数据库表名 t_user——– 后台domian的实体类名User。这样很明显会操做报错。

所以我们的MyBtais-Plus为我们提供了一系列的注解,下面我们来正式学习他们

1.1 @TableName

在实体类上加上注解@TableName("t_user"),标识这个类所对应的表名是t_user,这样才可以成功映射到对应的字段。

@TableName("t_user")public class User {private Long id;private String userName;private Integer age;private String email;}

以上是通过注解的方式完成,我们也可以通过配置文件来设置

mybatis-plus: configuration:# 配置MyBatis日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config:db-config: # 配置MyBatis-Plus操作表的默认前缀 table-prefix: t_

通过table_prefix设置前缀只适用于数据库表有前缀的,如果表名与实体类名差别甚远,则建议使用注解

1.2 @TableId

MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认是基于雪花算法的策略生成idASSIGN_ID

【产生的问题】

  • 若实体类和表中表示主键的不是id,而是其他字段 如何匹配
  • 怎样实现数据库中的自增策略

【对策】

在实体类中uid属性上通过@TableId将其标识为主键,即可成功执行SQL语句

@TableName("t_user")public class User {@TableId(value = "id", type = IdType.AUTO)private Long id;private String userName;private Integer age;private String email;}

这里有必要说下,idType,这个IdType是MyBatis-plus里面所提供的一种主键生成策略的枚举类

【源码】

@Getterpublic enum IdType {/** * 数据库ID自增 * 

该类型请确保数据库设置了 ID自增 否则无效

*/
AUTO(0),/** * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) */NONE(1),/** * 用户输入ID *

该类型可以通过自己注册自动填充插件进行填充

*/
INPUT(2),/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 *//** * 分配ID (主键类型为number或string), * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法) * * @since 3.3.0 */ASSIGN_ID(3),/** * 分配UUID (主键类型为 string) * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-","")) */ASSIGN_UUID(4);private final int key;IdType(int key) {this.key = key;}}

也就是说MP提供了5种测类,下面简要的介绍其中的某些:

  • AUTO: 数据库自增策略,注意,该类型请确保数据库设置了id自增, 否则无效
  • NONE:MP set主键,雪花算法实现。就是如果传了id用传的,否则默认的雪花算法
  • INPUT:需要时开发者手动赋值,没写一样雪花算法自动生成
  • ASSIGN_ID: 雪花算法,默认,与数据库id是否设置了自增无关

1.3 @TableField

TableField与TableId的区别就是:

  • TableField适用于解决非主键字段不匹配的情况,而且TableField还可以指定那个字段查询的时候不显示
  • TableId主要解决主键不匹配的情况
@TableName("t_user")public class User {// 处理主键相关的字段名不一致 以及设置主键自增策略@TableId(value = "id", type = IdType.AUTO)private Long id;// 在mp种默认的设置可以将数据库中的字段名xxx_xxx转化为相应的驼峰命名@TableField(value = "user_name")private String userName;@TableField(value = "age")private Integer age;// exist=false 表示查询时候不显示@TableField(exist = false)private String email;}

当我们使用了@TableField(exist = false)则在查询的时候就不会显示查询出来的值

1.4 @TableLogic

逻辑删除
在我们的日常开发中,会经常遇到这种逻辑删除的操做,因为这样仍然会在数据库中保存这条数据,防止后期如果还想用的话还可以找到。我们要时刻铭记,数据的CUD操做,一定要谨慎,谨慎,再谨慎!!!

如果我们的业务对数据的要求是可以恢复的,我们就要使用逻辑删除操做,一般我们就在数据库种加一个字段is_deleted

  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
  • 使用场景:可以进行数据恢复
@TableName("t_user")public class User {// 处理主键相关的字段名不一致 以及设置主键自增策略@TableId(value = "id", type = IdType.AUTO)private Long id;// 在mp种默认的设置可以将数据库中的字段名xxx_xxx转化为相应的驼峰命名@TableField(value = "user_name")private String userName;@TableField(value = "age")private Integer age;@TableField(value = "email")private String email;// 逻辑删除 0 标识未删除 1表示删除了@TableLogicprivate Integer isDeleted;}

注意:当我们使用了逻辑删除则删除操作就变成了修改操作


  • 测试删除功能,真正执行的是修改
    UPDATE t_user SET is_deleted=1 WHERE id=" />

    【继承关系】

    • Wrapper : 条件构造抽象类,最顶端父类
      • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
        • QueryWrapper : 查询条件封装
        • UpdateWrapper : Update 条件封装
        • AbstractLambdaWrapper : 使用Lambda 语法
          • LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
          • LambdaUpdateWrapper : Lambda 更新封装Wrapper

    这里主要就是介绍QueryWrapper和UpdateWrapper

    2.1 QueryWrapper


    上图是BaseMapper里面的关于参数是Warpper的方法,下面我们一一介绍:

    2.1.1 组装查询条件selectCount

    /** * 测试wraper封装查询条件1 ** @throws Exception */@Testpublic void testQuery5() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>();// sql: SELECT COUNT( * ) FROM t_user WHERE is_deleted=0 AND (age BETWEEN " />// ?)queryWrapper.between("age", 18, 23);Long list = userMapper.selectCount(queryWrapper);System.out.println(list);}

    2.1.2 组装查询条件selectList

    /** * 测试wraper封装查询条件2 ** @throws Exception */@Testpublic void testQuery9() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>();// SELECT id,user_name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND// (email IS NOT NULL AND email LIKE ?)queryWrapper.isNotNull("email").like("email", "163.com");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}

    2.1.3 组装查询参数selectMaps

    /** * 测试wraper封装查询条件3 ** @throws Exception */@Testpublic void testQuery10() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>();// SELECT age,email,user_name FROM t_user WHERE is_deleted=0queryWrapper.select("age", "email", "user_name");List<Map<String, Object>> list = userMapper.selectMaps(queryWrapper);list.forEach(System.out::println);}

    2.1.4 组装查询selectOne

    /** * 测试wraper封装查询条件4 ** @throws Exception */@Testpublic void testQuery11() {QueryWrapper<User> queryWrapper = new QueryWrapper<User>();// SELECT age,email,user_name FROM t_user WHERE is_deleted=0 AND (user_name = ?)queryWrapper.select("age", "email", "user_name");queryWrapper.eq("user_name", "test");User list = userMapper.selectOne(queryWrapper);System.out.println(list);}

    根据上述的方法,我们可以很轻松地观察到,querywrapper里面封装了许多的方法就是用于设置我们的查询条件,而且比较通俗易懂,比如ge大于等于between介于等等,这里只演示这些,剩下的自己在开发中用到继续摸索。


    2.1.5 调整条件优先级

    注意:
    这里说明下如何调整参数的优先级,我们都知道在sql中可以通过()完成查询条件的优先级提升,那么在MP中如何操做???

    【代码演示】
    通过and方法,利用lambda表达式实现

    @Testpublic void testQuery7() throws Exception {User user = new User();// 将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改user.setEmail("modifyTest@gogel.com");QueryWrapper<User> queryWrapper = new QueryWrapper<User>();// UPDATE t_user SET age=?, email=? WHERE (user_name LIKE ? AND (age > ? OR email IS NULL))queryWrapper.like("user_name", "a").and(i -> i.ge("age", 20).or().isNull("email"));List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}

    2.1.6 实现子查询inSql

    @GetMapping("/queryZI")public List<User> queryZI() {// SELECT id,user_name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (id IN ( SELECT id FROM t_user WHERE id <=100))QueryWrapper<User> queryWrapper = new QueryWrapper<User>();queryWrapper.inSql("id", " SELECT id FROM t_user WHERE id <=100");List<User> maps = userMapper.selectList(queryWrapper);return maps;}

    2.2 UpdateWrapper

    2.2.1 组装修改条件update

    @Testpublic void testUpdate2() throws Exception {User user = new User();user.setEmail("modifyTest@gogel.com");UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>();updateWrapper.ge("age", 20).like("user_name", "a").or().isNull("email");/** * 根据 whereEntity 条件,更新记录 * * @param entity实体对象 (set 条件值,可以为 null) 修改的参数 * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)条件参数 */int row = userMapper.update(user, updateWrapper);log.info("删除数据={}条", row);}

    三、MyBatis-Plus分页插件

    MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能

    3.1 实现步骤

    1️⃣添加配置类

    /** * MybatisPlus的分页插件配置类 * @author wangruoxian * */@Configuration@MapperScan("com.wei.mapper")public class MyBatisPlusPageConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}}

    2️⃣ 测试

    @GetMapping("/page")public IPage<User> pageList(){Page<User> page = new Page<User>(1,3);//QueryWrapper queryWrapper = new QueryWrapper();//// 当前页码//page.setCurrent(1);//// 每页显示的条数//page.setSize(5);IPage<User> selectPage = userMapper.selectPage(page, null);log.info("当前页数={}",selectPage.getCurrent());log.info("总页数={}",selectPage.getPages());selectPage.getRecords().forEach(System.out::println);log.info("每页大小={}",selectPage.getSize());log.info("总数据条数={}",selectPage.getTotal());return selectPage;}

    四、通用枚举

    表中的有些字段值是固定的,例如性别(男或女),此时我们可以使用MyBatis-Plus的通用枚举来实现

    4.1 数据库表添加字段sex

    4.2 配置扫描通用枚举

    # 配置扫描通用枚举type-enums-package: com.wei.enums

    4.3 新建枚举类

    @Getterpublic enum SexEnum {MALE(0,"男"),FEMALE(1,"女");@EnumValueprivate Integer sexCode;private String sexValue;private SexEnum(Integer sexCode, String sexValue) {this.sexCode = sexCode;this.sexValue = sexValue;}}

    4.3.1 @EnumValue注解

    通用的枚举类注解,将数据库字段映射成实体类的枚举类型成员变量

    将枚举改成成员变量和数据库的字段映射起来,根据数据库字段的值找到对应枚举的对象

    4.4 测试