学习要求
良好的java基础, 熟悉SpringBoot框架,熟悉Mybatis框架
教程目标
1>系统了解MyBatis-Plus
2>体验一把MyBatis-Plus骚操作
视频教程
引出Mybatis-Plus
回顾Mybatis操作MySQL
1>创建数据库,创建表
2>创建项目,导入逆向工程相对应的依赖与配置
3>逆向工程创建实体/mapper接口/mapper.xml映射文件
4>导入mybatis依赖,mysql依赖
5>编写测试类,测试mapper接口实现CRUD操作
分析:
项目中,每张表对应一个实体类,对应一个mapper.java接口, 对应一个mapper.xml配置文件,并且每个mapper.java接口都有重复的crud方法,每一个Mapper.xml都有重复的crud的sql配置语句。使用逆向工程自动创建这些貌似也没多麻烦,但是,如果一个项目复杂了,这些文件就膨胀了,加载、维护就麻烦很多了。此时不禁想,有没有某种方法不写crud方法,不写crud sql语句也能完成crud操作呢?答案是Yes: 使用Mybatis-plus!!
Mybatis了解
下面是官网抄的,省着看~
MyBatis-Plus(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
具有特性
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
支持的数据库:Mybatis支持的,它都支持
架构图
MyBatis与MyBatis-Plus区别
MyBatis
优点:
1>SQL语句自由控制,较为灵活
2>SQL与业务代码分离,易于阅读与维护
3>提供动态SQL语句,可以根据需求灵活控制
缺点:
1>简单的crud操作也必须提供对应SQL语句
2>必须维护大量的xml文件
3>自身功能有限,要拓展只能依赖第三方插件
MyBatis-plus 是在Mybatis的基础上进行二次开发的具有MyBatis所有功能, 也添加了不少好用的功能
比如:
1>提供无sql 的crud操作
2>内置代码生成器,分页插件, 性能分析插件等
3>提供功能丰富的条件构造器快速进行无sql开发
......
入门案例
1>创建数据库mybatis-plus,并创建employee表,并导入数据
CREATE TABLE `employee` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`admin` bit(1) DEFAULT NULL,
`dept_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
INSERT INTO `employee` VALUES (1, 'admin', '1', 'admin@abc.com', 40, b'1', 6);
INSERT INTO `employee` VALUES (2, '赵总', '1', 'zhaoz@wolfcode.cn', 35, b'0', 1);
INSERT INTO `employee` VALUES (3, '赵一明', '1', 'zhaoym@wolfcode.cn', 25, b'0', 1);
INSERT INTO `employee` VALUES (4, '钱总', '1', 'qianz@wolfcode.cn', 31, b'0', 2);
INSERT INTO `employee` VALUES (5, '钱二明', '1', 'qianem@wolfcode.cn', 25, b'0', 2);
INSERT INTO `employee` VALUES (6, '孙总', '1', 'sunz@wolfcode.cn', 35, b'0', 3);
INSERT INTO `employee` VALUES (7, '孙三明', '1', 'sunsm@wolfcode.cn', 25, b'0', 3);
INSERT INTO `employee` VALUES (8, '李总', '1', 'liz@wolfcode.cn', 35, b'0', 4);
INSERT INTO `employee` VALUES (9, '李四明', '1', 'lism@wolfcode.cn', 25, b'0', 4);
INSERT INTO `employee` VALUES (10, '周总', '1', 'zhouz@wolfcode.cn', 19, b'0', 5);
INSERT INTO `employee` VALUES (11, '周五明', '1', 'zhouwm@wolfcode.cn', 25, b'0', 5);
INSERT INTO `employee` VALUES (12, '吴总', '1', 'wuz@wolfcode.cn', 41, b'0', 5);
INSERT INTO `employee` VALUES (13, '吴六明', '1', 'wulm@wolfcode.cn', 33, b'0', 5);
INSERT INTO `employee` VALUES (14, '郑总', '1', 'zhengz@wolfcode.cn', 35, b'0', 3);
INSERT INTO `employee` VALUES (15, '郑七明', '1', 'zhengqm@wolfcode.cn', 25, b'0', 2);
INSERT INTO `employee` VALUES (16, '孙四明', '1', 'sunsim@wolfcode.cn', 25, b'0', 3);
INSERT INTO `employee` VALUES (17, '孙五明', '1', 'sunwm@wolfcode.cn', 25, b'0', 3);
INSERT INTO `employee` VALUES (18, '李五明', '1', 'liwm@wolfcode.cn', 25, b'0', 4);
INSERT INTO `employee` VALUES (19, '李六明', '1', 'lilm@wolfcode.cn', 25, b'0', 4);
INSERT INTO `employee` VALUES (20, 'xiaofei', '111', 'dafei@wolfcode.cn', 0, b'0', 1);
2>创建springboot项目-mybatis-plus-demo
3>pom.xml文件中导入springboot依赖、mybatis-plus依赖、其他依赖等
<!--springboot项目导入依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
</parent>
<dependencies>
<!--springboot项目基本组件依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!--数据连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--测试依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--自动生成getter/setter方法依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
</dependencies>
4>在application.properties文件中配置数据库连接四要素与日志
#mysql
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-plus?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 配置sql打印日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
5>编写Employee实体类与mapper接口
@Setter
@Getter
@ToString
public class Employee {
private Long id;
private String name;
private String password;
private String email;
private int age;
private int admin;
private Long deptId;
}
/**
* 持久层映射接口:mybatis-plus
* mybatis-plus mapper接口自定义
* 1:自定义一个接口, 继承BaseMapper
* 2:指定接口泛型:当前接口操作实体对象:Employee
*/
public interface EmployeeMapper extends BaseMapper<Employee> {
}
6>编写启动类,指定mapper接口扫描路径
@SpringBootApplication
//mapper接口所在的包路径
@MapperScan(basePackages = "com.langfeiyes.mp.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
7>编写测试类
@SpringBootTest
public class CRUDTest {
@Autowired
private EmployeeMapper employeeMapper;
@Test
public void testSave(){
Employee employee = new Employee();
employee.setAdmin(1);
employee.setAge(18);
employee.setDeptId(1L);
employee.setEmail("zhangsan@163.com");
employee.setName("zhangsan");
employee.setPassword("111");
employeeMapper.insert(employee);
}
@Test
public void testUpdate(){
Employee employee = new Employee();
employee.setId(1327139013313564673L);
employee.setAdmin(1);
employee.setAge(18);
employee.setDeptId(1L);
employee.setEmail("zhangsan@163.com");
employee.setName("zhangxiaosan");
employee.setPassword("111");
employeeMapper.updateById(employee);
}
@Test
public void testDelete(){
employeeMapper.deleteById(11L);
}
@Test
public void testGet(){
System.out.println(employeeMapper.selectById(11L));
}
@Test
public void testList(){
List<Employee> employees = employeeMapper.selectList(null);
employees.forEach(System.err::println);
}
}
8>运行testList方法
观察SQL
执行成功。
分析
思考2个问题:
1>EmployeeMapper 接口没有定义crud方法,为什么在CRUDTest测试类中可以调用crud方法?
答:EmployeeMapper接口继承了BaseMapper接口,BaseMapper接口自定义了很多crud方法,所以即使EmployeeMapper接口没写,它也可以从BaseMapper接口继承而来。
2>整个项目没有编写SQL语句,为什么可以实现CRUD操作,比如上面查询可以打印出查询sql?
答:项目中没有,但是又能执行,说明了啥?说明了Mybatis-Plus框架帮我们实现了。那怎么实现的呢?
以selectList为例子,
实现员工列表的SQL:
SELECT id,name,password,email,age,admin,dept_id FROM employee
这里最核心的是啥?表: employee ,列:id,name,password,email,age,admin,dept_id
那如果mybatis-plus能通过某种手段拼接出表,列那么sql不就完成了么。但这又引出一个问题,mybatis-plus是怎么找到当前执行方法应该操作那个表,哪些列呢?
观察下面接口:
public interface EmployeeMapper extends BaseMapper<Employee> {
}
继承的BaseMapper<Employee>接口中指定一个Employee泛型,那么可以这么推测,mybatis-plus通过获取指定的泛型,然后解析该类型得到Employee类字节码对象,然后通过反射操作获取这个字节码对象的类名作为表名,字段名作为列名,那么上面说的表, 列不就齐了么?是的mybatis-plus本质就是这么做的。我们看回mybatis-plus架构图
单看左边,也能大体推测出mybatis-plus操作原理:
1>扫描实体对象,通过反射获取实体对象对应的表,对应的列
2>解析表, 列名,做各种适配,然后根据调用的方法拼接出各种CRUD SQL语句
3>将拼接好的SQL语句交给mybatis容器执行。
到这Mybatis-Plus的helloword就介绍啦。
源码:传送门