Spring Boot(十一)集成MyBatis-Plus

我会带着你远行 2023-05-21 05:59 37阅读 0赞

文章目录

    • 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

更多介绍请看官网说明

快速开始

  1. 引入依赖




    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

项目整体目录结构

在这里插入图片描述

数据库准备

  1. -- 用户表:user
  2. DROP TABLE IF EXISTS `user`;
  3. CREATE TABLE `user` (
  4. `id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
  5. `name` VARCHAR(30) DEFAULT NULL COMMENT '姓名',
  6. `age` INT(11) DEFAULT NULL COMMENT '年龄',
  7. `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
  8. `manager_id` BIGINT(20) DEFAULT NULL COMMENT '直属上级id',
  9. `create_time` DATETIME(0) DEFAULT NULL COMMENT '创建时间',
  10. `update_time` DATETIME DEFAULT NULL COMMENT '修改时间',
  11. `version` INT(11) DEFAULT '1' COMMENT '版本',
  12. `deleted` INT(1) DEFAULT '0' COMMENT '逻辑删除标识(0.未删除,1.已删除)'
  13. ) ENGINE=INNODB CHARSET=UTF8;
  14. INSERT INTO `user`(`id`,`name`,`age`,`email`,`manager_id`,`create_time`) VALUES
  15. (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL, '2019-01-11 14:20:20'),
  16. (1088248166370832385, '王天风', 25, 'wtf@baomidou.com', 1087982257332887553, '2019-02-05 11:12:22'),
  17. (1088250446457389058, '李艺伟', 28, 'lyw@baomidou.com', 1088248166370832385, '2019-02-14 08:31:16'),
  18. (1094590409767661570, '张雨琪', 31, 'zjq@baomidou.com', 1088248166370832385, '2019-01-14 09:15:15'),
  19. (1094592041087729666, '刘红雨', 32, 'lhm@baomidou.com', 1088248166370832385, '2019-01-14 09:48:16');

配置文件

application.yml

  1. # 配置数据源
  2. spring:
  3. datasource:
  4. driver-class-name: com.mysql.jdbc.Driver
  5. url: jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
  6. username: root
  7. password: 123456
  8. # 配置日志
  9. logging:
  10. level:
  11. root: warn
  12. com.zou.dao: trace
  13. pattern:
  14. console: '%p%m%n'

MyBatisPlusConfig 配置类

  1. @EnableTransactionManagement
  2. @Configuration
  3. @MapperScan("com.zou.dao")
  4. public class MyBatisPlusConfig {
  5. // 分页插件配置,如果不需要配置分页插件可以省略这个配置类,
  6. //然后将 @MapperScan("com.zou.dao")配置在springBoot启动类上即可
  7. @Bean
  8. public PaginationInterceptor paginationInterceptor() {
  9. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
  10. // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
  11. // paginationInterceptor.setOverflow(false);
  12. // 设置最大单页限制数量,默认 500 条,-1 不受限制
  13. // paginationInterceptor.setLimit(500);
  14. // 开启 count 的 join 优化,只针对部分 left join
  15. paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
  16. return paginationInterceptor;
  17. }
  18. }

简单CRUD

  1. 新建实体类

User

  1. @Data
  2. public class User {
  3. private Long id;
  4. private String name;
  5. private Integer age;
  6. private String email;
  7. private Long managerId;
  8. private LocalDateTime createTime;
  9. private LocalDateTime updateTime;
  10. }

传统 mybatis写CRUD需要写接口加xml来完成,这里MyBatis-Plus直接帮我们封装好了简单的单表CRUD,我们写的mapper接口继承 BaseMapper这个泛型接口即可,其中T为你要操作的实体类

UserMapper

  1. @Repository
  2. public interface UserMapper extends BaseMapper<User> {
  3. // 自定义分页
  4. IPage<User> selectPage(Page<User> page,
  5. @Param("User") User user);
  6. }

自定义分页返回参数转换

  1. @Data
  2. public class PageInfoVO<R> {
  3. private List<R> list;
  4. /** * 总页数 */
  5. private long pages;
  6. /** * 总数 */
  7. private long total;
  8. /** * 每页大小(默认 10) */
  9. private Integer pageSize;
  10. /** * 当前页 */
  11. private long pageNo;
  12. public Integer getPageSize() {
  13. return Optional.ofNullable(this.pageSize).orElse(10);
  14. }
  15. public PageInfoVO() {
  16. this.total = 0;
  17. this.list = Lists.newArrayListWithExpectedSize(0);
  18. }
  19. public PageInfoVO(int pageNo,int pageSize){
  20. this.pageNo = pageNo;
  21. this.pageSize = pageSize;
  22. this.list = Lists.newArrayList();
  23. }
  24. /** * 获取总页数 * @param * @return long * @author wh * @date 2020/9/21 */
  25. public long getPages(){
  26. if (pages != 0) {
  27. return pages;
  28. }
  29. Integer pageSize = getPageSize();
  30. return total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
  31. }
  32. public PageInfoVO(Integer total, List<R> list){
  33. this.list = list;
  34. this.total = total;
  35. }
  36. /** * T 为目标类型 MybatisPlus Page转PageInfoVO * @param page * @param klass * @param <E> 入参类型 */
  37. public <E> PageInfoVO(IPage<E> page, Class<R> klass) {
  38. this.total = page.getTotal();
  39. this.pages = page.getPages();
  40. this.pageNo = page.getCurrent();
  41. Function<E, R> function = (e) -> {
  42. R object = BeanUtils.instantiateClass(klass);
  43. BeanUtils.copyProperties(e, object);
  44. return object;
  45. };
  46. this.list = page.getRecords().stream().map(function).collect(Collectors.toList());
  47. }
  48. /** * spirng page 转 PageInfoVO * @param page * @param klass * @return * @author wh * @date 2020/9/21 */
  49. public <E> PageInfoVO(Page<E> page, Class<R> klass) {
  50. this.total = page.getTotalElements();
  51. this.pages = page.getTotalPages();
  52. Function<E, R> function = (e) -> {
  53. R object = BeanUtils.instantiateClass(klass);
  54. BeanUtils.copyProperties(e, object);
  55. return object;
  56. };
  57. this.list = page.getContent().stream().map(function).collect(Collectors.toList());
  58. }
  59. }

使用

  1. LambdaQueryWrapper<CustomerLabelMapping> wrapper = Wrappers.lambdaQuery();
  2. wrapper.like(StrUtil.isNotBlank(labelQuery.getDrugId()), CustomerLabelMapping::getDrugId, labelQuery.getDrugId())
  3. .eq(CustomerLabelMapping::getCustomerId, labelQuery.getCustomerId());
  4. Page page = new Page(labelQuery.getPageNo(), labelQuery.getPageSize());
  5. return new PageInfoVO<CustomerLabelMapping>(super.page(page, wrapper), CustomerLabelMapping.class);

我们可以看到BaseMapper源码中已经给我们封装好了大量的单表操作
在这里插入图片描述

只需要这样我们就可以完成简单的CRUD了

创建一个测试类试试吧

  1. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  3. import com.baomidou.mybatisplus.core.metadata.IPage;
  4. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  5. import com.zou.Application;
  6. import com.zou.dao.UserMapper;
  7. import com.zou.entity.User;
  8. import com.zou.service.UserService;
  9. import org.junit.Test;
  10. import org.junit.runner.RunWith;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.boot.test.context.SpringBootTest;
  13. import org.springframework.test.context.junit4.SpringRunner;
  14. import java.util.Arrays;
  15. import java.util.List;
  16. /** * @author WH * @version 1.0 * @date 2020/5/5 11:23 * @Description TODO */
  17. @RunWith(SpringRunner.class)
  18. @SpringBootTest(classes = Application.class)
  19. public class SelectTest {
  20. static User user;
  21. static {
  22. user = new User();
  23. user.setName("阿离");
  24. user.setAge(18);
  25. user.setEmail("641884200@qq.com");
  26. }
  27. @Autowired
  28. private UserMapper userMapper;
  29. @Autowired
  30. private UserService userService;
  31. /** * 通过id查询 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE id=1088248166370832385; */
  32. @Test
  33. public void selectById() {
  34. User user = userMapper.selectById(1088248166370832385L);
  35. }
  36. /** * 条件查询 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE (name = '阿离' AND age > 18 OR email IS NOT NULL); */
  37. @Test
  38. public void selectByCondition() {
  39. QueryWrapper<User> wrapper = new QueryWrapper<>();
  40. wrapper.eq("name", "阿离").gt("age", 18).or().isNotNull("email");
  41. List<User> users = userMapper.selectList(wrapper);
  42. print(users);
  43. }
  44. /** 通过user 查询 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE name='阿离' AND age=18 AND email='641884200@qq.com'; */
  45. @Test
  46. public void selectByUser() {
  47. QueryWrapper<User> wrapper = new QueryWrapper<>(user);
  48. List<User> users = userMapper.selectList(wrapper);
  49. print(users);
  50. }
  51. /** * 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)); */
  52. @Test
  53. public void selectLambda() {
  54. LambdaQueryWrapper<User> lambda = new QueryWrapper<User>().lambda();
  55. lambda.like(User::getAge, "雨").
  56. and(q -> q.lt(User::getAge, 40).or().isNotNull(User::getEmail));
  57. userMapper.selectList(lambda);
  58. }
  59. /** * 拼接在sql最后 * SELECT id,name,age,email,manager_id,create_time * FROM user * WHERE (age IN (30,31,32)) * LIMIT 1; */
  60. @Test
  61. public void selectOne() {
  62. QueryWrapper<User> wrapper = new QueryWrapper<>();
  63. wrapper.in("age", Arrays.asList(30, 31, 32)).last("limit 1");
  64. List<User> users = userMapper.selectList(wrapper);
  65. }
  66. /** * 查询指定字段 */
  67. @Test
  68. public void selectColum() {
  69. QueryWrapper<User> wrapper = new QueryWrapper<>(user);
  70. wrapper.select("name", "age");
  71. userMapper.selectList(wrapper);
  72. }
  73. /** * 排除指定字段 * SELECT id,name,manager_id,create_time,update_time * FROM user * WHERE name='阿离' AND age=18 AND email='641884200@qq.com'; */
  74. @Test
  75. public void selectExclude() {
  76. QueryWrapper<User> wrapper = new QueryWrapper<>(user);
  77. wrapper.select(User.class, s ->
  78. !s.getColumn().equals("email") && !s.getColumn().equals("age")
  79. );
  80. List<User> users = userMapper.selectList(wrapper);
  81. }
  82. /** * 分组排序求和 * 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; */
  83. @Test
  84. public void selectGroupBy() {
  85. QueryWrapper<User> wrapper = new QueryWrapper<>(user);
  86. wrapper.select("avg(age) age", "min(id)").groupBy("id")
  87. .having("avg(age)<{0}", 30);
  88. List<User> users = userMapper.selectList(wrapper);
  89. }
  90. /** * 分页 */
  91. @Test
  92. public void selectPage() {
  93. LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
  94. lambda.ge(User::getAge,26).orderByDesc(User::getCreateTime);
  95. Page<User> page = new Page<> (1,2);
  96. IPage<User> userIPage = userMapper.selectPage(page, lambda);
  97. System.out.println("总页数:"+userIPage.getPages());
  98. System.out.println("总记录数:"+userIPage.getTotal());
  99. List<User> list = userIPage.getRecords();
  100. print(list);
  101. }
  102. /** * 一条sql不查询总记录数 减少性能消耗 */
  103. @Test
  104. public void selectPageNotCount() {
  105. LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
  106. lambda.ge(User::getAge,26).orderByDesc(User::getCreateTime);
  107. Page<User> page = new Page<> (1,2, false);//不查记录数
  108. IPage<User> userIPage = userMapper.selectPage(page, lambda);
  109. System.out.println("总页数:"+userIPage.getPages());
  110. System.out.println("总记录数:"+userIPage.getTotal());
  111. List<User> list = userIPage.getRecords();
  112. print(list);
  113. }
  114. /** * 自定义分页 */
  115. @Test
  116. public void selectCustom() {
  117. Page<User> page = new Page<>(1, 3);
  118. IPage<User> userIPage = userMapper.selectPage(page, user);
  119. System.out.println("总页数:"+userIPage.getPages());
  120. System.out.println("总记录数:"+userIPage.getTotal());
  121. print(userIPage.getRecords());
  122. }
  123. public static void print(List<User> users) {
  124. users.forEach(s -> System.out.println("姓名:" + s.getName()));
  125. }
  126. }

查询中包含了单表分页,自定义分页update、delete操作与查询类似

通用service

如果BaseMapper操作没有满足还可以进一步使用 IService,里面有更多的操作数据库方法
在这里插入图片描述

用法很简单,最好的做法是在mapper封装一层DAO,不要在Service层继承,那样dao就可以拥有所有mybatis方法了,大致使用如下
在这里插入图片描述

在这里插入图片描述

详细方法可以参考官网

源码下载

源码

发表评论

表情:
评论列表 (有 0 条评论,37人围观)

还没有评论,来说两句吧...

相关阅读