Mybatis-Plus使用手册

本文最后更新于:2021年4月15日 上午

🌟 HelloWorld

(1)初始化SpringBoot工程

(2)导入依赖

<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>

<!--mysql依赖-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

(3)在application中配置数据库信息

# 应用名称
spring.application.name=mybatis_plus_demo

# 数据库配置信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root

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

# 主键自增
#mybatis-plus.global-config.db-config.id-type=auto

(4)在主引导类上添加扫描包注解@MapperScan("com.gaowl.mybatis_plus_demo.mapper")

(5)创建包entity及实体类User.java

(6)创建包mapper及接口UserMapper.java

// 在接口上通过注释@Repository 避免无法自动装配
// Mapper 继承 BaseMapper接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
@Repository
public interface UserMapper extends BaseMapper<User> {

}

(7)测试即可

@SpringBootTest
class MybatisPlusDemoApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }

    @Test
    public void testAdd(){
        User user = new User();
        user.setId(6L);
        user.setName("李四");
        user.setAge(20);
        user.setEmail("11111@qq.com");
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }

    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(1372867719975714818L);
        user.setName("lucymary233");
        int count = userMapper.updateById(user);
        System.out.println(count);
    }

    @Test
    public void testOptimisticLocker(){
        User user = userMapper.selectById(6L);
        user.setName("张三");
        userMapper.updateById(user);
    }

}

🌟 主键策略

MyBatis Plus默认的主键策略是:ASSIGN_ID(使用了雪花算法,分布式ID生成器)

雪花算法:由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。长度共64bit(一个long型) 19位数字

整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高,用的也比较多。

image-20210319224002874

MyBatis Plus支持的主键策略还有AUTO 自增

实体字段中配置 @TableId(type = IdType.AUTO)

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

要想影响所有实体的配置,可以设置全局主键配置

#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto

🌟 自动填充与乐观锁

项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作

(1)修改数据库

在User表中添加datetime类型的新的字段 create_timeupdate_time

(2)修改实体类

实体类上增加字段并添加自动填充注解

// 添加元素的时候自动赋值
@TableField(fill = FieldFill.INSERT)
private Date createTime;

// 添加和更新元素时均自动赋值
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

(3)实现元对象处理器接口

package com.gaowl.mybatis_plus_demo.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    //mp执行添加操作,这个方法执行
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
        this.setFieldValByName("version",1,metaObject);
    }

    //mp执行修改操作,这个方法执行
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

(4)测试即可,每次创建对象时自动对create_timeupdate_time字段赋值,更新对象时对update_time赋值

乐观锁主要用于实现线程安全的数据更新,当要更新一条记录的时候,希望这条记录没有被别人更新。

  • 取出记录时,获取当前version

  • 更新时,带上这个version

  • 执行更新时, set version = newVersion where version = oldVersion

  • 如果version不对,就更新失败

Mybatis-Plus中的乐观锁使用:

(1)修改实体类

新建version字段,并添加@Version注解

@Version
private Integer version;

(2)创建配置文件,并注册乐观锁插件

创建包config及文件MybatisPlusConfig.java

@Configuration
@MapperScan("com.atguigu.demomptest.mapper")
public class MpConfig {
    /**
     * 注册乐观锁插件
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

(3)测试即可

🌟 查询

(1)多个id批量查询

使用selectBatchIds命令实现多个id的批量查询

@Test
public void testSelect1() {
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    System.out.println(users);
}

(2)条件查询

selectByMap命令,通过map封装查询条件;注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id

@Test
public void testSelect2() {
    Map<String, Object> columnMap = new HashMap<>();
    columnMap.put("name","Jack");
    columnMap.put("age",20);
    List<User> users = userMapper.selectByMap(columnMap);
    System.out.println(users);
}

(3)分页查询

需先在配置类中添加分页插件

/**
 * 分页插件
 */
@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

之后采用selectPage命令进行分页查询

@Test
public void testSelectPage() {
    Page<User> page = new Page(1,3);
    Page<User> userPage = userMapper.selectPage(page, null);
    //返回对象得到分页所有数据
    long pages = userPage.getPages(); //总页数
    long current = userPage.getCurrent(); //当前页
    List<User> records = userPage.getRecords(); //查询数据集合
    long total = userPage.getTotal(); //总记录数
    boolean hasNext = userPage.hasNext();  //下一页
    boolean hasPrevious = userPage.hasPrevious(); //上一页

    System.out.println(pages);
    System.out.println(current);
    System.out.println(records);
    System.out.println(total);
    System.out.println(hasNext);
    System.out.println(hasPrevious);
}

🌟 删除

(1)根据id删除数据 deleteById

@Test
public void testDeleteById(){
    int result = userMapper.deleteById(5L);
	system.out.println(result);
}

(2)批量删除数据 deleteBatchIds

@Test
public void testDeleteBatchIds() {
    int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
	system.out.println(result);
}

(3)条件删除 deleteByMap

@Test
public void testDeleteByMap() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("name", "Helen");
    map.put("age", 18);
    
    int result = userMapper.deleteByMap(map);
    system.out.println(result);
}

(4)逻辑删除

概念

  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据

  • 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录

逻辑删除的使用场景:

  • 可以进行数据恢复

  • 有关联数据,不便删除

实现流程:

  • 数据库中添加delete字段:ALTERTABLE user ADD COLUMN deleted boolean DEFAULT false

  • 实体类中添加deleted字段,并加上@TableLogic注解

  • application.yml中添加默认值配置

    mybatis-plus.global-config.db-config.logic-delete-value=1
    mybatis-plus.global-config.db-config.logic-not-delete-value=0
  • 测试

    @Test
    public void testLogicDelete() {
       int result = userMapper.deleteById(1L);
    	system.out.println(result);
    }

    测试后发现,数据并没有被删除,deleted字段的值由0变成了1;测试后分析打印的sql语句,是一条update。

    注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作

🌟 条件构造器wrapper实现复杂查询

无标题

查询方式 说明
setSqlSelect 设置 SELECT 查询字段
where WHERE 语句,拼接 + WHERE 条件
and AND 语句,拼接 + AND 字段=值
andNew AND 语句,拼接 + AND (字段=值)
or OR 语句,拼接 + OR 字段=值
orNew OR 语句,拼接 + OR (字段=值)
eq 等于=
allEq 基于 map 内容等于=
ne 不等于<>
gt 大于>
ge 大于等于>=
lt 小于<
le 小于等于<=
like 模糊查询 LIKE
notLike 模糊查询 NOT LIKE
in IN 查询
notIn NOT IN 查询
isNull 是否为空
isNotNull 非空
groupBy 分组 GROUP BY
having HAVING 关键词
orderBy 排序 ORDER BY
orderAsc ASC 排序 ORDER BY
orderDesc DESC 排序 ORDER BY
exists EXISTS 条件语句
notExists NOT EXISTS 条件语句
between BETWEEN 条件语句
notBetween NOT BETWEEN 条件语句
addFilter 自由拼接 SQL
last 拼接在最后,例如:last(“LIMIT 1”)

(1)ge、gt、le、lt、isNull、isNotNull

@Test
public void testQuery() {
    // 新建QueryWrapper实例,并传入实体类类型
	QueryWrapper<User> queryWrapper = new QueryWrapper<>();
	queryWrapper
        .isNull("name")
        .ge("age", 12)
        .isNotNull("email");
    
    // 删除符合此查询条件(name为空,年龄大于等于12且邮箱非空)的数据
    int result = userMapper.delete(queryWrapper);
	System.out.println("delete return count = " + result);
}

(2)eq、ne

@Test
public void testSelectOne() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("name", "Tom");
    
    Useruser = userMapper.selectOne(queryWrapper);//只能返回一条记录,多于一条则抛出异常
    System.out.println(user);
}

(3)between、notBetween

@Test
public void testSelectCount() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.between("age", 20, 30);
    
    Integer count = userMapper.selectCount(queryWrapper); //返回数据数量
    System.out.println(count);
}

(4)like、notLike、likeLeft、likeRight

selectMaps()返回Map集合列表,通常配合select()使用

@Test
public void testSelectMaps() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
            .select("name", "age")
            .like("name", "e")  // name中包含e
            .likeRight("email", "5");  // 
    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);//返回值是Map列表
    maps.forEach(System.out::println);
}

(5)orderBy、orderByDesc、orderByAsc

@Test
public void testSelectListOrderBy() {
    QueryWrapper<User>queryWrapper = newQueryWrapper<>();
    queryWrapper.orderByDesc("age", "id");
    
    List<User>users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!