前面用了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. 分页查询
分页查询的实现步骤:
- 配置分页插件
- 在Mapper接口编写分页查询接口
- 编写SQL语句,查询数据库
- 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官网。如果有什么问题,欢迎大家在评论区指出。