MyBatis教程[8]----使用MyBatis-Plus简化开发

前面用了7篇博客,讲完了mybatis。掌握了前面7篇博客的内容,便可以自如应对spring下的mybatis开发了。

然而,很多时候Mybatis的表现并不是那么完美,比如很多简单的CURD语句还需要开发者手动完成;不支持分页功能,需要开发者写代码实现分页逻辑等等。。。。

这时候,就不得不提MyBatis-Plus了,MyBatis-Plus正是为简化Mybatis的开发而诞生的。

1. MyBatis-Plus介绍

官网关于MyBatis-Plus简介的第一句话就是:

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

只做增强,不做改变。这意味着原来写的MyBatis代码可以直接拿来用在MyBatis-Plus上,而几乎不用做任何修改。
在这里插入图片描述
就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

在这里直接贴上官网对MP的特性介绍:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

本文将演示一下SpringBoot + MyBatis-Plus项目环境的搭建,以及使用MyBatis-Plus内置的CRUD,以及演示分页。

2. SpringBoot整合MyBatis-Plus

2.1 新建SpringBoot项目

第一步:新创建SpringBoot项目,这一步前面已经做了很多次了,不详细说了。

新创建好的项目的目录结构:
在这里插入图片描述

2.2 添加依赖

需要添加的依赖有:

  • mysql-connector-java:数据库驱动
  • lombok:可自动生成Getter、Setter、toString方法
  • mybatis-plus-boot-starter:mybatis-plus启动器

添加依赖:

<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<!--自动生成Getter、Setter、toString方法的插件-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

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

2.3 配置数据源以及mybatis-plus

spring:
  datasource:
    username: root
    password: 123
    #mysql8以上的驱动包需要指定以下时区
    url: jdbc:mysql://127.0.0.1:23306/study-mybatis?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  # 指定实体类所有包
  type-aliases-package: com.yky.springboot.entities
  # 指定xml映射配置文件扫描路径
  mapper-locations: classpath:mapper/*.xml

2.4 创建实体类

在entities包下创建User类,代码为下:

package com.yky.springboot.entities;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
public class User implements Serializable {
	//指定一下主键id
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private String phone;
    private Date birthday;
}

2.5 创建Mapper接口

package com.yky.springboot.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yky.springboot.entities.User;
import org.apache.ibatis.annotations.Mapper;

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

在这里,只需要继承BaseMapper接口,甚至不用写mapper映射配置文件,便可直接使用MP内部的CRUD操作接口。

MP默认提供了以下操作CRUD接口:

/**
 * 插入一条记录
 *
 * @param entity 实体对象
 */
int insert(T entity);

/**
 * 根据 ID 删除
 *
 * @param id 主键ID
 */
int deleteById(Serializable id);

/**
 * 根据 columnMap 条件,删除记录
 *
 * @param columnMap 表字段 map 对象
 */
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

/**
 * 根据 entity 条件,删除记录
 *
 * @param wrapper 实体对象封装操作类(可以为 null)
 */
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

/**
 * 删除(根据ID 批量删除)
 *
 * @param idList 主键ID列表(不能为 null 以及 empty)
 */
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

/**
 * 根据 ID 修改
 *
 * @param entity 实体对象
 */
int updateById(@Param(Constants.ENTITY) T entity);

/**
 * 根据 whereEntity 条件,更新记录
 *
 * @param entity        实体对象 (set 条件值,可以为 null)
 * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
 */
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

/**
 * 根据 ID 查询
 *
 * @param id 主键ID
 */
T selectById(Serializable id);

/**
 * 查询(根据ID 批量查询)
 *
 * @param idList 主键ID列表(不能为 null 以及 empty)
 */
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

/**
 * 查询(根据 columnMap 条件)
 *
 * @param columnMap 表字段 map 对象
 */
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

/**
 * 根据 entity 条件,查询一条记录
 *
 * @param queryWrapper 实体对象封装操作类(可以为 null)
 */
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

/**
 * 根据 Wrapper 条件,查询总记录数
 *
 * @param queryWrapper 实体对象封装操作类(可以为 null)
 */
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

/**
 * 根据 entity 条件,查询全部记录
 *
 * @param queryWrapper 实体对象封装操作类(可以为 null)
 */
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

/**
 * 根据 Wrapper 条件,查询全部记录
 *
 * @param queryWrapper 实体对象封装操作类(可以为 null)
 */
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

/**
 * 根据 Wrapper 条件,查询全部记录
 * <p>注意: 只返回第一个字段的值</p>
 *
 * @param queryWrapper 实体对象封装操作类(可以为 null)
 */
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

/**
 * 根据 entity 条件,查询全部记录(并翻页)
 *
 * @param page         分页查询条件(可以为 RowBounds.DEFAULT)
 * @param queryWrapper 实体对象封装操作类(可以为 null)
 */
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

/**
 * 根据 Wrapper 条件,查询全部记录(并翻页)
 *
 * @param page         分页查询条件
 * @param queryWrapper 实体对象封装操作类
 */
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

开发者可直接调用这些接口方法操作数据库,而无须关心接口的内部实现,大大简化了开发,提高了开发效率。

2.6 创建Service层

在Web开发中,Controller层调用Service层代码,业务逻辑写在Service层;Service层调用Dao层代码(这里的Dao层就是Mapper接口),Dao层操作数据库。所以,一般情况下还需要开发Service层。

Service接口需要这样写:

package com.yky.springboot.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.yky.springboot.entities.User;

public interface UserService extends IService<User> {
}

光有Service接口还不够,还需要有接口实现:

package com.yky.springboot.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yky.springboot.entities.User;
import com.yky.springboot.mapper.UserMapper;
import com.yky.springboot.service.UserService;
import org.springframework.stereotype.Service;

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

只需要继承ServiceImpl类便可直接调用Mapper接口的方法了,因为Service层是面向接口编程,所以我们还继承了前面写的UserService接口。

至此,Dao层、Service层均已创建好了。

如果想在Service层的实现类中调用Mapper代码,直接用baseMapper即可(所继承的ServiceImpl中有注入Mapper进来):
在这里插入图片描述

3. 单元测试

@SpringBootTest
class UserServiceTest {

    @Autowired
    UserService userService;

    /**
     * 新增或修改数据(如果主键id不为空,且id已在数据库中存在了,则进行更新操作)
     */
    @Test
    public void insert() throws ParseException {
        User user = new User();
        user.setName("法外狂徒张三");
        user.setPhone("11111111111");
        user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("1996-07-18"));

        userService.saveOrUpdate(user);
    }

    /**
     * 删除数据
     */
    @Test
    public void delete() {
        userService.removeById(1);
    }


    /**
     * 获取所有
     */
    @Test
    public void selectAll() {
        List<User> users = userService.list();

        System.out.println(users);
    }

    /**
     * 根据id获取
     */
    @Test
    public void getById() {
        User user = userService.getById(1);
        System.out.println(user);
    }

}

至此,我们没有写任何的xml映射配置代码,就已经完成了对数据库的大部分操作。接下来,我们来完成一下分页。

4. 分页查询

分页查询的实现步骤:

  1. 配置分页插件
  2. 在Mapper接口编写分页查询接口
  3. 编写SQL语句,查询数据库
  4. Service层调用分页查询接口

4.1 配置分页插件

新创建config.MybatisPlusConfig并写入以下代码:

package com.yky.springboot.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * mybatisPlus配置
 */
@EnableTransactionManagement//开启事务管理
//@MapperScan("com.mengxuegu.web.mapper")//扫描Mapper接口,就不需要在Mapper接口上加Mapper注解了
@Configuration
public class MybatisPlusConfig {

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

4.2 编写分页查询接口

/**
 * 分页查询接口
 * @param page 分页对象
 * @param user 用于查询的实体对象
 * @return 分页数据
 */
IPage<User> selectPage(Page<User> page,@Param("user") User user);

Page对象的属性:

public class Page<T> implements IPage<T> {
/**
     * 查询数据列表
     */
    private List<T> records = Collections.emptyList();

    /**
     * 总数
     */
    private long total = 0;
    /**
     * 每页显示条数,默认 10
     */
    private long size = 10;

    /**
     * 当前页
     */
    private long current = 1;

    /**
     * 排序字段信息
     */
    private List<OrderItem> orders = new ArrayList<>();

    /**
     * 自动优化 COUNT SQL
     */
    private boolean optimizeCountSql = true;
    /**
     * 是否进行 count 查询
     */
    private boolean isSearchCount = true;
    /**
     * 是否命中count缓存
     */
    private boolean hitCount = false;
}

我们可以设置page对象的size、current属性来进行分页查询,查询结果封装在records中。

4.3 编写xml映射配置文件

在resources/mapper目录下创建UserMapper.xml文件,并写入以下代码:

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--namespace对应Mapper接口的全类名,这样就可以自动匹配上-->
<mapper namespace="com.yky.springboot.mapper.UserMapper">
    <select id="selectPage" resultType="User">
        SELECT
            *
        FROM `user`

        <where>
            <if test="user.name != null and user.name != ''">
                name LIKE CONCAT('%',#{user.name},'%')
            </if>

            <if test="user.phone != null and user.phone != ''">
                AND `phone` = #{user.phone}
            </if>
        </where>
    </select>
</mapper>

在这里,都不需要写LIMIT语句,MyBatis-Plus会自动帮我们添加上(根据传入的Page对象,自动生成LIMIT语句)。

4.4 单元测试测试Dao层代码

@Autowired
UserMapper userMapper;
@Test
public void selectPage() {
    User user = new User();
    user.setName("小");
    IPage<User> userPage = userMapper.selectPage(new Page<User>(),user);

    System.out.println(userPage.getRecords());
}

4.5 编写Service层分页查询代码

编写Service接口:

/**
 * 分页查询数据
 * @param size 单页大小
 * @param current 当前页码
 * @param user 用于查询的实体对象
 * @return 分页数据
 */
IPage<User> selectPage(long size, long current, User user);

编写接口实现:

    @Override
public IPage<User> selectPage(long size, long current, User user) {
    Page page = new Page();
    page.setSize(size);
    page.setCurrent(current);

    return baseMapper.selectPage(page,user);
}

单元测试Service层代码

@Test
public void selectPage() {
    User user = new User();
    user.setName("小");
    IPage<User> page = userService.selectPage(3, 1, user);
    System.out.println(page.getRecords());
    System.out.println(page.getTotal());
}

至此,使用MyBatis-Plus进行分页查询的功能开发完成,相比于手写分页简单多了。关于使用MyBatis-Plus简化MyBatis开发就讲到这里了,如果想了解更多可移步MyBatis-Plus官网。如果有什么问题,欢迎大家在评论区指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章