Spring Boot(十一)集成MyBatis-Plus
文章目录
- MyBatis-Plus
- 特性
- 快速开始
- 项目整体目录结构
- 数据库准备
- 配置文件
- 简单CRUD
- 通用service
- 源码下载
MyBatis-Plus
官网
个人白话解释:简单的CRUD直接通过方法调用,无需多写接口和xml,像jpa那样调用
愿景
我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
更多介绍请看官网说明
快速开始
引入依赖
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
true
com.baomidou
mybatis-plus-boot-starter
3.3.1.tmp
mysql
mysql-connector-java
5.1.48
com.google.guava
guava
28.2-jre
说明核心依赖 mybatis-plus-boot-starter
项目整体目录结构
数据库准备
-- 用户表:user
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
`name` VARCHAR(30) DEFAULT NULL COMMENT '姓名',
`age` INT(11) DEFAULT NULL COMMENT '年龄',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
`manager_id` BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
`create_time` DATETIME(0) DEFAULT NULL COMMENT '创建时间',
`update_time` DATETIME DEFAULT NULL COMMENT '修改时间',
`version` INT(11) DEFAULT '1' COMMENT '版本',
`deleted` INT(1) DEFAULT '0' COMMENT '逻辑删除标识(0.未删除,1.已删除)'
) ENGINE=INNODB CHARSET=UTF8;
INSERT INTO `user`(`id`,`name`,`age`,`email`,`manager_id`,`create_time`) VALUES
(1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL, '2019-01-11 14:20:20'),
(1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553, '2019-02-05 11:12:22'),
(1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385, '2019-02-14 08:31:16'),
(1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385, '2019-01-14 09:15:15'),
(1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385, '2019-01-14 09:48:16');
配置文件
application.yml
# 配置数据源
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: 123456
# 配置日志
logging:
level:
root: warn
com.zou.dao: trace
pattern:
console: '%p%m%n'
MyBatisPlusConfig 配置类
@EnableTransactionManagement
@Configuration
@MapperScan("com.zou.dao")
public class MyBatisPlusConfig {
// 分页插件配置,如果不需要配置分页插件可以省略这个配置类,
//然后将 @MapperScan("com.zou.dao")配置在springBoot启动类上即可
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
简单CRUD
- 新建实体类
User
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
private Long managerId;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
传统 mybatis写CRUD需要写接口加xml来完成,这里MyBatis-Plus直接帮我们封装好了简单的单表CRUD,我们写的mapper接口继承 BaseMapper这个泛型接口即可,其中T为你要操作的实体类
UserMapper
@Repository
public interface UserMapper extends BaseMapper<User> {
// 自定义分页
IPage<User> selectPage(Page<User> page,
@Param("User") User user);
}
自定义分页返回参数转换
@Data
public class PageInfoVO<R> {
private List<R> list;
/** * 总页数 */
private long pages;
/** * 总数 */
private long total;
/** * 每页大小(默认 10) */
private Integer pageSize;
/** * 当前页 */
private long pageNo;
public Integer getPageSize() {
return Optional.ofNullable(this.pageSize).orElse(10);
}
public PageInfoVO() {
this.total = 0;
this.list = Lists.newArrayListWithExpectedSize(0);
}
public PageInfoVO(int pageNo,int pageSize){
this.pageNo = pageNo;
this.pageSize = pageSize;
this.list = Lists.newArrayList();
}
/** * 获取总页数 * @param * @return long * @author wh * @date 2020/9/21 */
public long getPages(){
if (pages != 0) {
return pages;
}
Integer pageSize = getPageSize();
return total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
}
public PageInfoVO(Integer total, List<R> list){
this.list = list;
this.total = total;
}
/** * T 为目标类型 MybatisPlus Page转PageInfoVO * @param page * @param klass * @param <E> 入参类型 */
public <E> PageInfoVO(IPage<E> page, Class<R> klass) {
this.total = page.getTotal();
this.pages = page.getPages();
this.pageNo = page.getCurrent();
Function<E, R> function = (e) -> {
R object = BeanUtils.instantiateClass(klass);
BeanUtils.copyProperties(e, object);
return object;
};
this.list = page.getRecords().stream().map(function).collect(Collectors.toList());
}
/** * spirng page 转 PageInfoVO * @param page * @param klass * @return * @author wh * @date 2020/9/21 */
public <E> PageInfoVO(Page<E> page, Class<R> klass) {
this.total = page.getTotalElements();
this.pages = page.getTotalPages();
Function<E, R> function = (e) -> {
R object = BeanUtils.instantiateClass(klass);
BeanUtils.copyProperties(e, object);
return object;
};
this.list = page.getContent().stream().map(function).collect(Collectors.toList());
}
}
使用
LambdaQueryWrapper<CustomerLabelMapping> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(labelQuery.getDrugId()), CustomerLabelMapping::getDrugId, labelQuery.getDrugId())
.eq(CustomerLabelMapping::getCustomerId, labelQuery.getCustomerId());
Page page = new Page(labelQuery.getPageNo(), labelQuery.getPageSize());
return new PageInfoVO<CustomerLabelMapping>(super.page(page, wrapper), CustomerLabelMapping.class);
我们可以看到BaseMapper源码中已经给我们封装好了大量的单表操作
只需要这样我们就可以完成简单的CRUD了
创建一个测试类试试吧
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zou.Application;
import com.zou.dao.UserMapper;
import com.zou.entity.User;
import com.zou.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import java.util.List;
/** * @author WH * @version 1.0 * @date 2020/5/5 11:23 * @Description TODO */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class SelectTest {
static User user;
static {
user = new User();
user.setName("阿离");
user.setAge(18);
user.setEmail("641884200@qq.com");
}
@Autowired
private UserMapper userMapper;
@Autowired
private UserService userService;
/** * 通过id查询 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE id=1088248166370832385; */
@Test
public void selectById() {
User user = userMapper.selectById(1088248166370832385L);
}
/** * 条件查询 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE (name = '阿离' AND age > 18 OR email IS NOT NULL); */
@Test
public void selectByCondition() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "阿离").gt("age", 18).or().isNotNull("email");
List<User> users = userMapper.selectList(wrapper);
print(users);
}
/** 通过user 查询 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE name='阿离' AND age=18 AND email='641884200@qq.com'; */
@Test
public void selectByUser() {
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
List<User> users = userMapper.selectList(wrapper);
print(users);
}
/** * lambda 条件构造器 防误写 * SELECT id,name,age,email,manager_id,create_time,update_time * FROM user * WHERE (age LIKE '%雨%' AND (age < 40 OR email IS NOT NULL)); */
@Test
public void selectLambda() {
LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
lambda.like(User::getAge, "雨").
and(q -> q.lt(User::getAge, 40).or().isNotNull(User::getEmail));
userMapper.selectList(lambda);
}
/** * 拼接在sql最后 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE (age IN (30,31,32)) * LIMIT 1; */
@Test
public void selectOne() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.in("age", Arrays.asList(30, 31, 32)).last("limit 1");
List<User> users = userMapper.selectList(wrapper);
}
/** * 查询指定字段 */
@Test
public void selectColum() {
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
wrapper.select("name", "age");
userMapper.selectList(wrapper);
}
/** * 排除指定字段 * SELECT id,name,manager_id,create_time,update_time * FROM user * WHERE name='阿离' AND age=18 AND email='641884200@qq.com'; */
@Test
public void selectExclude() {
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
wrapper.select(User.class, s ->
!s.getColumn().equals("email") && !s.getColumn().equals("age")
);
List<User> users = userMapper.selectList(wrapper);
}
/** * 分组排序求和 * SELECT avg(age) age,min(id) * FROM user * WHERE name='阿离' AND age=18 AND email='641884200@qq.com' GROUP BY id HAVING avg(age)<30; */
@Test
public void selectGroupBy() {
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
wrapper.select("avg(age) age", "min(id)").groupBy("id")
.having("avg(age)<{0}", 30);
List<User> users = userMapper.selectList(wrapper);
}
/** * 分页 */
@Test
public void selectPage() {
LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
lambda.ge(User::getAge,26).orderByDesc(User::getCreateTime);
Page<User> page = new Page<> (1,2);
IPage<User> userIPage = userMapper.selectPage(page, lambda);
System.out.println("总页数:"+userIPage.getPages());
System.out.println("总记录数:"+userIPage.getTotal());
List<User> list = userIPage.getRecords();
print(list);
}
/** * 一条sql不查询总记录数 减少性能消耗 */
@Test
public void selectPageNotCount() {
LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
lambda.ge(User::getAge,26).orderByDesc(User::getCreateTime);
Page<User> page = new Page<> (1,2, false);//不查记录数
IPage<User> userIPage = userMapper.selectPage(page, lambda);
System.out.println("总页数:"+userIPage.getPages());
System.out.println("总记录数:"+userIPage.getTotal());
List<User> list = userIPage.getRecords();
print(list);
}
/** * 自定义分页 */
@Test
public void selectCustom() {
Page<User> page = new Page<>(1, 3);
IPage<User> userIPage = userMapper.selectPage(page, user);
System.out.println("总页数:"+userIPage.getPages());
System.out.println("总记录数:"+userIPage.getTotal());
print(userIPage.getRecords());
}
public static void print(List<User> users) {
users.forEach(s -> System.out.println("姓名:" + s.getName()));
}
}
查询中包含了单表分页,自定义分页update、delete操作与查询类似
通用service
如果BaseMapper操作没有满足还可以进一步使用 IService,里面有更多的操作数据库方法
用法很简单,最好的做法是在mapper封装一层DAO,不要在Service层继承,那样dao就可以拥有所有mybatis方法了,大致使用如下
详细方法可以参考官网
源码下载
源码
还没有评论,来说两句吧...