一、MyBatisPlus简介

1.1. 简介

  • 润物无声

只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。

  • 效率至上

只需简单配置,即可快速进行单表 CRUD 操作,从而节省大量时间。

  • 丰富功能

代码生成、自动分页、逻辑删除、自动填充等功能一应俱全。

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。具有无侵入,损耗小,提供强大CRUD操作、支持 Lambda、内置分页插件等特性。其内部提供了大量的默认方法供我们调用,大大简化了操作数据库的步骤。

1.2. 准备工作

1.2.1. 引入依赖

<!--起步类-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.1</version>
</dependency>
<!--可选:德鲁伊连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.9</version>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
</dependency>

1.2.2. 设置常用配置

此处以mysql的配置连接为例

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://IP:端口/数据库名?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    username: 数据库用户名
    password: 数据库密码
mybatis-plus:
  configuration:
    # 可选项:默认的enum处理器,用于处理实体类中的枚举项存入数据库时的转换
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
    # sql日志输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    field-strategy: 0
    db-config:
      logic-delete-field: deleted
      # 默认id生成策略:雪花算法
      id-type: assign_id

1.2.3. 定义实体类

需要注意,实体类上需要添加@TableName并指定对应的表名,id上使用@TableId注解标记id,指定id的名字,或者额外指定id生成策略。使用@TableField指定其他字段,可以通过赋值value属性进行映射。

如果希望某个敏感字段在查询语句时默认不被查询,则使用@TableField(select= false)注明

如果普通字段的名字和数据库里的字段能够对应,就可以省略@TableFile注解。如果实体类中有非数据库的字段,需要使用注解@TableField(exist = false)注明,否则可能会报错!

package link.xiaomo.user.domain.po;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.tianji.user.enums.UserStatus;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 用户表
 *
 * @author Mosfield
 */
@Data
@TableName("t_user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 手机号
     */
    @TableField("cell_phone")
    private String cellPhone;

    /**
     * 密码
     */
    private String password;

    /**
     * 账户状态:0-禁用,1-正常
     */
    private UserStatus status;

    /**
     * 创建时间
     */
    @TableField("create_time")
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    @TableField("update_time")
    private LocalDateTime updateTime;

    /**
     * 创建者id
     */
    private Long creator;

    /**
     * 修改者id
     */
    private Long updater;

    /**
     * 权限列表,非数据库字段
     */
    @TableField(exist = false)
    private List<Role> roleList;
}

1.2.4. 定义mapper

需要继承BaseMapper,泛型为具体的实体类

package link.xiaomo.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import link.xiaomo.user.domain.po.User;
import org.apache.ibatis.annotations.Mapper;

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

1.2.5. 定义Service

可以通过继承ServiceImpl,继承很多默认实现的方法。需要注意根据实体类填写对应的泛型

另外,继承ServiceImpl不是必须的,目的是使用默认方法,请按需添加

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    ........
}

1.2.6. 配置分页插件

package link.xiaomo.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //1 创建MybatisPlusInterceptor拦截器对象
        MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
        //2 添加分页拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mpInterceptor;
    }
}

二、标准数据层开发

2.1. Mapper常用api

在service层,通过调用对应实体类的Mapper接口,可以调用如下从BaseMapper继承的通用方法。

功能 api
新增 int insert(T t)
删除 int deleteById(Serializable id)
修改 int updateById(T t)
根据id查询 T selectById(Serializable id)
查询全部 List selectList()
分页查询 IPage selectPage(IPage page)
按条件查询 IPage selectPage(wrapper querywrapper)

同时,如果你的service继承了ServiceImpl,那也可以通过 this.方法名的方式,使用ServiceImpl提供的默认方法。但是这些默认方法和mapper提供的方法,方法名可能不同,需要注意。

2.2. 分页功能

请务必务必务必完成步骤1.2.6的分页配置

// 普通查询条件
QueryWrapper<User> queryWrappe = new QueryWrapper<>();
queryWrappe.eq("groupId", 18);

//1 创建IPage分页对象,设置分页参数
IPage<User> page=new Page<>(1,3);
//2 执行分页查询
userDao.selectPage(page,queryWrappe);
//3 获取分页结果
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());

三、条件查询方式

3.1 条件查询

普通条件查询

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

lambda格式按条件查询

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

3.2 组合条件

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

在多数的QueryWrapper中,如果第一个参数是boolean类型,说明如果第一个参数为true时,才会把这个查询条件加到最终的查询中。如果为false,则相当于没有这个查询条件。

Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//参数1:如果表达式为true,那么查询才使用该条件
lqw.gt(minAge!=null,User::getAge, minAge);
lqw.lt(maxAge!=null,User::getAge, maxAge);
List<User> userList = userDao.selectList(lqw);
userList.forEach(System.out::println);
  • 链式编程
Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//参数1:如果表达式为true,那么查询才使用该条件
lqw.gt(minAge!=null,User::getAge, minAge)
   .lt(maxAge!=null,User::getAge, maxAge);
List<User> userList = userDao.selectList(lqw);
userList.forEach(System.out::println);

四、查询投影

4.1. 只查询部分属性

如果只查询结果中的部分属性,使用如下方法

LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.select(User::getId, User::getName, User::getAge);
List<User> userList = userDao.selectList(lqw);

QueryWrapper<User> lqw = new QueryWrapper<User>();
lqw.select("id", "name", "age", "tel");
List<User> userList = userDao.selectList(lqw);

4.2. 查询未定义的属性

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);

投影查询如果用到了自定义结果,则结果不适合用目标对象结果。可以用map接受,也可以根据结果定义一个DTO对象进行接受

这时候其实更建议使用在xml中自定义sql

五、其他设置

5.1. id生成策略

5.1.1. id生成策略控制

  • 名称:@TableId

  • 类型:属性注解

  • 位置:模型类中用于表示主键的属性定义上方

  • 作用:设置当前类中主键属性的生成策略

  • 主键生成策略:通过type属性设置主键属性的生成策略,值参照IdType枚举值

    • AUTO 使用数据库的策略
    • NONE 不设置id生成策略
    • INPUT 用户手工输入id
    • ASSIGN_ID 雪花算法生成id
    • ASSIGN_UUID uuid生成id

5.1.2. 全局策略配置

设定全局策略以后,如果不设置id策略,就按全局策略走,单独设置的话就按单独的设置来。

如果设置了表名前缀,并且不指名表名的话,就按前缀+实体类名当做表名

mybatis-plus:
  global-config:
    db-config:
      # 全局id生成策略
      id-type: assign_id
      # 全局表名前缀
      table-prefix: tbl_

5.2. 批量Delete/Select

5.2.1 按照主键删除多条记录

//删除指定多条数据
List<Long> list = new ArrayList<>();
list.add(1402551342481838081L);
list.add(1402553134049501186L);
list.add(1402553619611430913L);

userDao.deleteBatchIds(list);

5.2.2 根据主键查询多条记录

//查询指定多条数据
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(3L);
list.add(4L);
userDao.selectBatchIds(list);
如人饮水,冷暖自知。
最后更新于 2023-08-05