第 1 章 MybatisPlus 快速入门

本是古典 何须时尚 2023-01-17 15:55 371阅读 0赞

第 1 章 MybatisPlus 快速入门

1、MybatisPlus 概述

MybatisPlus:一款 Mybatis 的增强工具包

MybatisPlus 官网:https://mybatis.plus/ 或 https://mp.baomidou.com/

image-20210417183056916

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

愿景:我们的愿景是成为 MyBatis 最好的搭档,就像魂斗罗中的 1P、2P,基友搭配,效率翻倍。

MybatisPlus 的特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

MybatisPlus 文档地址

  1. 官方地址:http://mp.baomidou.com 或者 https://mybatis.plus/
  2. 代码发布地址:

    1. Github:https://github.com/baomidou/mybatis-plus
    2. Gitee:https://gitee.com/baomidou/mybatis-plus
  3. 文档发布地址:https://mp.baomidou.com/guide/

2、MybatisPlus 快速入门

2.1、环境搭建

0、参考资料

MybatisPlus 快速开始

1、创建数据库表

现有一张 User 表,其表结构如下










































id name age email
1 Jone 18 test1@baomidou.com
2 Jack 20 test2@baomidou.com
3 Tom 28 test3@baomidou.com
4 Sandy 21 test4@baomidou.com
5 Billie 24 test5@baomidou.com

其对应的数据库 Schema 脚本和 Data 脚本如下:

  1. -- 创建数据库
  2. CREATE DATABASE mybatis_plus;
  3. -- 使用数据库
  4. USE mybatis_plus;
  5. -- 创建数据库表
  6. DROP TABLE IF EXISTS USER;
  7. CREATE TABLE USER
  8. (
  9. id BIGINT(20) NOT NULL COMMENT '主键ID',
  10. NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
  11. age INT(11) NULL DEFAULT NULL COMMENT '年龄',
  12. email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
  13. PRIMARY KEY (id)
  14. );
  15. -- 插入测试数据
  16. DELETE FROM USER;
  17. INSERT INTO USER (id, NAME, age, email) VALUES
  18. (1, 'Jone', 18, 'test1@baomidou.com'),
  19. (2, 'Jack', 20, 'test2@baomidou.com'),
  20. (3, 'Tom', 28, 'test3@baomidou.com'),
  21. (4, 'Sandy', 21, 'test4@baomidou.com'),
  22. (5, 'Billie', 24, 'test5@baomidou.com');

Question:如果从零开始用 MyBatis-Plus 来实现该表的增删改查我们需要做什么呢?

2、引入依赖

引入 Spring Boot Starter 作为当前工程的父工程:

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.2.2.RELEASE</version>
  5. </parent>

引入 spring-boot-starterspring-boot-starter-testmybatis-plus-boot-startermysql 依赖:

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-test</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.projectlombok</groupId>
  8. <artifactId>lombok</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>mysql</groupId>
  12. <artifactId>mysql-connector-java</artifactId>
  13. </dependency>
  14. <dependency>
  15. <groupId>com.baomidou</groupId>
  16. <artifactId>mybatis-plus-boot-starter</artifactId>
  17. <version>3.4.2</version>
  18. </dependency>
  19. </dependencies>

3、创建实体类以及 Mapper 映射接口

创建 User 实体类:实体类的字段最好使用包装类型,而不要使用基本类型。因为每个基本类型都有一个默认值,在查询的时候,就不好区分是数据库记录的值,还是字段的默认值。但是包装类型没有,如果没有为包装类型设置值,那么其值为 null

  1. /**
  2. * @Author Oneby
  3. * @Date 2021/4/18 17:53
  4. */
  5. @Data
  6. @AllArgsConstructor
  7. @NoArgsConstructor
  8. public class User {
  9. private Long id;
  10. private String name;
  11. private Integer age;
  12. private String email;
  13. }

创建 UserMapper 映射接口,该接口继承了 BaseMapper<User> 接口

  1. /**
  2. * @Author Oneby
  3. * @Date 2021/4/18 17:53
  4. */
  5. @Repository
  6. public interface UserMapper extends BaseMapper<User> {
  7. }

4、创建主启动类

在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 接口所在的包

  1. /**
  2. * @Author Oneby
  3. * @Date 2021/4/18 17:51
  4. */
  5. @SpringBootApplication
  6. @MapperScan("com.oneby.mapper")
  7. public class MybatisPlusApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(MybatisPlusApplication.class, args);
  10. }
  11. }

5、编写配置文件

在 application.yml 配置文件中配置数据源信息。注意:低版本 MySQL 驱动为 com.mysql.jdbc.Driver,无需配置时区;高版本 MySQL 驱动为 com.mysql.cj.jdbc.Driver,需要增加时区的配置

  1. # 数据源配置
  2. spring:
  3. datasource:
  4. driver-class-name: com.mysql.cj.jdbc.Driver
  5. url: jdbc:mysql://localhost:3307/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
  6. username: root
  7. password: root

6、代码测试

编写测试代码

  1. @RunWith(SpringRunner.class):这是 junit 提供的注解,该注解让测试运行于Spring测试环境,并让 SpringRunner 这个类提供 Spring 测试上下文
  2. @SpringBootTest:SpringBoot 测试类的注解,该注解会启动 SpringBoot 应用,并在测试中创建 ApplicationContext 对象
  3. UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件

    /**

    • @Author Oneby
    • @Date 2021/4/18 17:54
      */
      @RunWith(SpringRunner.class)
      @SpringBootTest
      public class MybatisPlusEnvironmentTest {
  1. @Autowired
  2. private UserMapper userMapper;
  3. @Test
  4. public void testSelect() {
  5. List<User> userList = userMapper.selectList(null);
  6. userList.forEach(System.out::println);
  7. }
  8. }

程序运行结果:通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!

  1. User(id=1, name=Jone, age=18, email=test1@baomidou.com)
  2. User(id=2, name=Jack, age=20, email=test2@baomidou.com)
  3. User(id=3, name=Tom, age=28, email=test3@baomidou.com)
  4. User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
  5. User(id=5, name=Billie, age=24, email=test5@baomidou.com)

2.2、SQL 日志

查看 SQL 日志

为了能够观察调用每个方法时,MybatisPlus 到底为我们做了什么?执行了什么样的 SQL 语句?我们就需要开启 SQL 日志

  1. # SQL 日志配置
  2. mybatis-plus:
  3. configuration:
  4. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

开启日志之后,再次运行测试代码,可以看到调用 Mapper 方法时执行的 SQL 语句

  1. DBC Connection [HikariProxyConnection@81505591 wrapping com.mysql.cj.jdbc.ConnectionImpl@7b4acdc2] will not be managed by Spring
  2. ==> Preparing: SELECT id,name,age,email FROM user
  3. ==> Parameters:
  4. <== Columns: id, name, age, email
  5. <== Row: 1, Jone, 18, test1@baomidou.com
  6. <== Row: 2, Jack, 20, test2@baomidou.com
  7. <== Row: 3, Tom, 28, test3@baomidou.com
  8. <== Row: 4, Sandy, 21, test4@baomidou.com
  9. <== Row: 5, Billie, 24, test5@baomidou.com
  10. <== Total: 5
  11. Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@52a70627]
  12. User(id=1, name=Jone, age=18, email=test1@baomidou.com)
  13. User(id=2, name=Jack, age=20, email=test2@baomidou.com)
  14. User(id=3, name=Tom, age=28, email=test3@baomidou.com)
  15. User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
  16. User(id=5, name=Billie, age=24, email=test5@baomidou.com)

2.3、提出问题

我们都没有编写过CRUD 的接口以及实现,怎么就能执行基本的增删改查了呢?

我们自己编写的 UserMapper 类继承自 BaseMapper 接口,该接口中提供了基本的增删改查方法,因此我们自己编写的 Mapper 接口只需要继承 BaseMapper 父接口,就能获得基本的增删改查功能

  1. /**
  2. * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
  3. * <p>这个 Mapper 支持 id 泛型</p>
  4. *
  5. * @author hubin
  6. * @since 2016-01-23
  7. */
  8. public interface BaseMapper<T> extends Mapper<T> {
  9. /**
  10. * 插入一条记录
  11. *
  12. * @param entity 实体对象
  13. */
  14. int insert(T entity);
  15. /**
  16. * 根据 ID 删除
  17. *
  18. * @param id 主键ID
  19. */
  20. int deleteById(Serializable id);
  21. /**
  22. * 根据 columnMap 条件,删除记录
  23. *
  24. * @param columnMap 表字段 map 对象
  25. */
  26. int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
  27. /**
  28. * 根据 entity 条件,删除记录
  29. *
  30. * @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
  31. */
  32. int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  33. /**
  34. * 删除(根据ID 批量删除)
  35. *
  36. * @param idList 主键ID列表(不能为 null 以及 empty)
  37. */
  38. int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
  39. /**
  40. * 根据 ID 修改
  41. *
  42. * @param entity 实体对象
  43. */
  44. int updateById(@Param(Constants.ENTITY) T entity);
  45. /**
  46. * 根据 whereEntity 条件,更新记录
  47. *
  48. * @param entity 实体对象 (set 条件值,可以为 null)
  49. * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
  50. */
  51. int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
  52. /**
  53. * 根据 ID 查询
  54. *
  55. * @param id 主键ID
  56. */
  57. T selectById(Serializable id);
  58. /**
  59. * 查询(根据ID 批量查询)
  60. *
  61. * @param idList 主键ID列表(不能为 null 以及 empty)
  62. */
  63. List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
  64. /**
  65. * 查询(根据 columnMap 条件)
  66. *
  67. * @param columnMap 表字段 map 对象
  68. */
  69. List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
  70. /**
  71. * 根据 entity 条件,查询一条记录
  72. *
  73. * @param queryWrapper 实体对象封装操作类(可以为 null)
  74. */
  75. T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  76. /**
  77. * 根据 Wrapper 条件,查询总记录数
  78. *
  79. * @param queryWrapper 实体对象封装操作类(可以为 null)
  80. */
  81. Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  82. /**
  83. * 根据 entity 条件,查询全部记录
  84. *
  85. * @param queryWrapper 实体对象封装操作类(可以为 null)
  86. */
  87. List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  88. /**
  89. * 根据 Wrapper 条件,查询全部记录
  90. *
  91. * @param queryWrapper 实体对象封装操作类(可以为 null)
  92. */
  93. List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  94. /**
  95. * 根据 Wrapper 条件,查询全部记录
  96. * <p>注意: 只返回第一个字段的值</p>
  97. *
  98. * @param queryWrapper 实体对象封装操作类(可以为 null)
  99. */
  100. List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  101. /**
  102. * 根据 entity 条件,查询全部记录(并翻页)
  103. *
  104. * @param page 分页查询条件(可以为 RowBounds.DEFAULT)
  105. * @param queryWrapper 实体对象封装操作类(可以为 null)
  106. */
  107. <E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  108. /**
  109. * 根据 Wrapper 条件,查询全部记录(并翻页)
  110. *
  111. * @param page 分页查询条件
  112. * @param queryWrapper 实体对象封装操作类
  113. */
  114. <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
  115. }

诶,不对啊,BaseMapper 中之定义了接口,没有定义 SQL 语句呀。MybatisPlus 注入 SQL 的原理在后面会讲解,这里简单提一下。

我们以 Debug 的方式调试程序,找到 userMapper 中的 sqlSession --> sqlSessionFactory --> configuration --> mappedStatementsmappedStatements 的类型为 StrictMap,但其本质是 HashMapkeyString 类型,存储 Mapper 接口的方法名;valueMappedStatement 类型,存储接口方法对应的 SQL 信息。

image-20210418225711383

MappedStatement 中可以找到 com.oneby.mapper.UserMapper.selectById 方法对应的 SQL 语句为 SELECT id,name,age,email FROM user WHERE id=?,也就是 MybatisPlus 在加载 Mapper 接口时就已经帮我们创建好了其对应的 SQL 语句(这仅仅针对于能提前确定下来的简单 SQL 语句)

image-20210418225742458

对于 com.oneby.mapper.UserMapper.selectList 方法,其 SQL 语句不能提前确定下来,在 sqlSource 下就没有 sql 字段,取而代之的时 rootSqlNode 字段,该字段会根据条件构造器来动态拼接 SQL 语句

image-20210418230251507

发表评论

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

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

相关阅读