简介
官网 :https://baomidou.com/
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
支持的数据库
MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,
OceanBase,Firebird,Cubrid,Goldilocks,csiidb
快速开始
数据库数据
# 创建 user 表
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
# 向表中添加数据
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(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');
创建项目
创建一个 springboot 项目或 maven-quickstart 项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL连接数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!--MyBatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
配置数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=admin
创建实体
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
创建持久层接口(Mapper)
package com.hkp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hkp.entity.User;
//继承 BaseMapper 类 ,参数是实体类 ;里面封装了 CRUD 方法
public interface UserMapper extends BaseMapper<User> {
}
启动类添加注解,扫描持久层包
@MapperScan("com.hkp.mapper")
测试
package com.hkp;
import com.hkp.entity.User;
import com.hkp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
@SpringBootTest
public class AppTest {
@Resource
private UserMapper userMapper;
@Test
public void selectAll(){
//selectList() 方法的参数为 Mybatis-Plus 内置的条件封装器 Wrapper,所以不填写就是无任何条件
List<User> userList = userMapper.selectList(null);
//将所有用户循环输出
userList.forEach(System.out::println);
}
}
添加日志
添加日志,可以在控制台看到我们的SQL语句,有助于开发
修改 application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=admin
#开启日志 ,使用 log4j 等其他的日志 需要导包,这里使用默认的日志; 将日志打印到控制台
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
启动测试方法
注解
@TableName
描述
表名注解,标识实体类对应的表名
使用位置
实体类
package com.hkp.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("sys_user")
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
@TableId
描述
主键注解
使用位置
实体类主键字段
package com.hkp.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("sys_user")
@Data
public class User {
@TableId
private Long id;
private String name;
private Integer age;
private String email;
}
注解的属性
属性 | 类型 | 必须制定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 主键字段名 |
type | Enum | 否 | idType.NONE | 指定主键类型 |
idType 的值
值 | 描述 |
---|---|
AUTO | 数据库 ID 自增 |
NONE | 无状态,该类型为未设置主键类型 |
INPUT | insert 前自行 set 主键值 |
ASSIGN_ID | 分配 ID ,主键类型为 :Number ( Long 和 Integer ) 或 String |
ASSIGN_UUID | 分配 UUID ,主键类型为 :String |
@TableField
描述
字段注解(非主键)
package com.hkp.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("sys_user")
@Data
public class User {
@TableId
private Long id;
@TableField("username")
private String name;
private Integer age;
private String email;
}
主要属性
属性 | 类型 | 是否必须 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 主要用于 实体中 和 数据表 中名称不一致 |
fill | Enum | 否 | FieldFill.DEFAULT | 可以设置字段的自动填充规则,默认是可变的 |
FieldFill 的值
值 | 描述 |
---|---|
DEFAULT | 默认不处理 |
INSERT | 插入时填充字段 |
UPDATE | 更新时填充字段 |
INSERT_UPDATE | 插入和更新时填充字段 |
@Version
描述
乐观锁注解、标记
作用位置
字段上
@TableLogic
描述
表字段逻辑删除注解
属性
属性 | 类型 | 是否必须 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 逻辑未删除值 |
delval | String | 否 | “” | 逻辑删除值 |
CRUD
新增
1、在测试接口中测试
@Test
public void insertUser(){
User user=new User();
user.setName("测试数据");
user.setAge(12);
user.setEmail("123456@qq.com");
int insert = userMapper.insert(user);
System.out.println(insert);
System.out.println(user);
}
2、查看控制台日志效果
注意 :
可以看到,我并没有往实体中设置 id ,但是却自动加上了一个id
如果 主键 id 的类型为 Integer 默认的策略是 NONE
如果 主键id 的类型为 long 默认的策略是 ID_WORKER (雪花算法)
修改
1、在测试类中测试
@Test
public void updateUser(){
User user=new User();
user.setId(1310469473752416258L);
user.setName("测试数据update");
int i = userMapper.updateById(user);
System.out.println(i);
}
2、查看效果
从结果的 SQL 语句中可以看出 这个 修改是动态的修改,也就是需要修改什么属性就传什么属性,不需要修改就不传,保持原来的数据
查询
根据 id 查询
1、测试代码
@Test
public void selectById(){
User user = userMapper.selectById(1);
System.out.println(user);
}
2、查看结果
根据多个 ID 查询
1、测试代码
@Test
public void selectByIds(){
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
List<User> users = userMapper.selectBatchIds(ids);
users.forEach(System.out::println);
}
2、查看结果
多条件查询 Map
1、测试代码
@Test
public void selectByMap(){
//注意map中的 key 值必须是数据库的字段名
Map<String,Object> map=new HashMap<String,Object>();
map.put("name","Tom");
map.put("age",28);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
2、查看结果
分页查询
1、配置分页插件
// 低版本
@Configuration
public class MybatisConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
// 高版本
@Configuration
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
}
2、测试
@Test
public void SlectPage(){
//page 中第一个参数表示第几页,第二个参数表示一页中有多少条数据
Page<User> page=new Page<>(2,5);
userMapper.selectPage(page,null);
// 所有的结果都在 page 中 :查询出来的数据,总页数
List<User> userList = page.getRecords();
userList.forEach(System.out::println);
// 每页共有多少条数据
System.out.println(page.getSize());
//数据总条数
System.out.println(page.getTotal());
//共有多少页
System.out.println(page.getPages());
//是否还有下一页
System.out.println(page.hasNext());
//是否有上一页
System.out.println(page.hasPrevious());
}
3、查看效果
删除
根据 ID 删除
1、测试代码
@Test
public void deleteById(){
int num = userMapper.deleteById(2);
System.out.println(num);
}
2、查看效果
根据多个 ID 删除
1、测试代码
@Test
public void deleteByIds(){
List<Integer> ids = new ArrayList<>();
ids.add(4);
ids.add(5);
int num = userMapper.deleteBatchIds(ids);
System.out.println(num);
}
2、查看效果
多条件删除 Map
1、测试代码
@Test
public void deleteByMap(){
Map<String,Object> map = new HashMap<>();
//注意map中的 key 值必须是数据库的字段名
map.put("name","测试数据update");
int num = userMapper.deleteByMap(map);
System.out.println(num);
}
2、查看效果
逻辑删除
物理删除 :直接从数据库中删除了,数据永远没有了。
逻辑删除 :没有从数据库中删除,通过一个变量让他失效了。实际上执行的是一个 update 语句。
# 例如:
# 删除:
update user set deleted=1 where id = 1 and deleted=0
# 查找:
select id,name,deleted from user where deleted=0
实现步骤
1、在数据库中添加 变量 用来标记是否是逻辑删除 ,并给默认值为0
0 :逻辑未删除,1:逻辑已删除
2、在实体类中添加属性,并添加注解 @TableLogic
package com.hkp.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
@Data
public class User {
@TableId
private Long id;
private String name;
private Integer age;
private String email;
@TableLogic
private Integer deleted;
}
3、配置逻辑删除插件 ( 3.1.1 版本之后就不需要这个步骤了 )
@Configuration
public class MybatisConfig {
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
}
4、配置 application.properties 文件
# 全局逻辑删除的实体字段名
mybatis-plus.global-config.db-config.logic-delete-field=deleted
# 逻辑已删除值(默认为1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
执行 根据 id 删除语句,结果如下 :
执行根据 多个id 删除语句,结果如下 :
执行查询语句,结果如下 :
此时发现,查询的SQL 语句中加入了一个条件 where deleted=0
条件构造器 wrapper
更多知识去文档里学习 :
https://baomidou.com/pages/10c804/#abstractwrapper
like
语法 :
like(R column,Object val)
根据 姓名模糊查询
@Test
public void like(){
//根据姓名模糊查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name","j");
List<User> users = userMapper.selectList(wrapper);
//将所有用户循环输出
users.forEach(System.out::println);
}
运行结果
根据姓名左边模糊查询 和 右边模糊查询
@Test
public void like2(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.likeLeft("name","a")
.likeRight("name","j");
List<User> users = userMapper.selectList(wrapper);
//将所有用户循环输出
users.forEach(System.out::println);
}
运行结果
between
between and 左右均包含
语法 :
between(R column, Object val1, Object val2)
查询年龄在 20-30 岁之间
@Test
public void between(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age","12","28");
List<User> users = userMapper.selectList(wrapper);
//将所有用户循环输出
users.forEach(System.out::println);
}
运行结果
isNotNull
语法 :
isNotNull(R column)
查询姓名不为空的用户
@Test
public void isNotNull(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name");
List<User> users = userMapper.selectList(wrapper);
//将所有用户循环输出
users.forEach(System.out::println);
}
运行结果 :
eq
语法 :
eq(R column, Object val)
查询姓名等于 tom 的用户
@Test
public void eq(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","tom");
User user = userMapper.selectOne(wrapper);
//将所有用户循环输出
System.out.println(user);
}
运行结果 :
扩展
eq :等于
ne :不等于
ge
语法 :
ge(R column, Object val)
查询年龄大于等于28岁的用户
@Test
public void ge(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.ge("age",28);
List<User> users = userMapper.selectList(wrapper);
//将所有用户循环输出
users.forEach(System.out::println);
}
运行结果
扩展
gt :大于
ge :大于等于
lt :小于
le :小于等于
orderByDesc
语法 :
orderByDesc(R... columns) // 多个字段用逗号隔开
orderByDesc("id", "name")--->order by id DESC,name DES
根据 id 降序排序
@Test
public void desc(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
List<User> users = userMapper.selectList(wrapper);
//将所有用户循环输出
users.forEach(System.out::println);
}
运行结果
扩展
orderByAsc :升序
orderByDesc :降序