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 操作智能分析阻断,也可自定义拦截规则,预防误操作
更多介绍请看官网说明
快速开始
- 引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
</dependencies>
说明核心依赖 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);
}
我们可以看到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方法了,大致使用如下
详细方法可以参考官网
源码下载
转载:https://blog.csdn.net/qq_42651904/article/details/105934933
查看评论