单体框架总纲
1、简介
官网:https://mp.baomidou.com/
1、MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生
2、只做增强不做改变,引入它不会对现有工程产生影响
3、只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间。
4、热加载、代码生成、分页、性能分析等功能一应俱全。
目录结构:

2、创建 User表测试
1、建表语句
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)
);
2、插入数据
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');
3、初始化Springboot项目
1、引入maven 依赖
注意:引入 MyBatis-Plus 之后请不要再次引入 MyBatis,以避免因版本差异导致的问题
<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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
4、配置编写
1、spring boot 2.0(内置jdbc5驱动)
#mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=a1b2c3
2、spring boot 2.1及以上(内置jdbc8驱动)
注意:driver和url的变化
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=a1b2c3
3、细节说明:
- 这里的 url 使用了
?serverTimezone=GMT%2B8
后缀,因为8.0版本的jdbc驱动需要添加这个后缀,否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more - 这里的 driver-class-name 使用了 com.mysql.cj.jdbc.Driver ,在 jdbc 8 中 建议使用这个驱动,否则运行测试用例的时候会有 WARN 信息
5、代码编写
1、启动类编写:在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
@SpringBootApplication
@MapperScan("com.kk.mybatispulstest.mapper")
public class MybatisPulsTestApplication {
public static void main(String[] args) {
SpringApplication.run (MybatisPulsTestApplication.class, args);
}
}
2、对应实体类
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}

3、添加 mapper:创建包 mapper 编写Mapper 接口: UserMapper.java
@Repository //防止找不到这个Bean
public interface UserMapper extends BaseMapper<User> {
}
4、编写测试类:查询出所有
@SpringBootTest
class MybatisPulsTestApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void findAll(){
// 查询所有测试
List<User> users = userMapper.selectList (null);
System.out.println (users );
}
}
5、查看 sql 日志配置
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
6、主键策略
1、插入操作
// 添加
@Test
public void add(){
User user = new User ( );
user.setName ("my_kk");
user.setAge (27);
user.setEmail ("123@qq.com");
int insert = userMapper.insert (user);
System.out.println ("成功插入条数:"+insert );
}
2、MP主键策略
(1)ASSIGN_ID:MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法),
@TableId(type = IdType.ASSIGN_ID)
private String id;
(2)雪花算法:分布式ID生成器,由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性。
(3)雪花算法核心思想:
- 长度共64bit(一个long型)。
- 首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。
- 41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。
- 10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。
12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。
image.png
优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
3、AUTO 自增策略
(1)需要在创建数据表的时候设置主键自增,实体配置:
@TableId(type = IdType.AUTO)
private Long id;
(2)要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
4、取新增后的 ID
// 添加
@Test
public void add() {
User user = new User ( );
user.setName ("my_kk_主键返回测试");
user.setAge (27);
user.setEmail ("123@qq.com");
int insert = userMapper.insert (user);
System.out.println ("成功插入条数:" + insert);
System.out.println ("返回的id:" + user.getId ());
}
7、自动填充和乐观锁
1、自动填充
(1)传统更新操作:
@Test
public void update() {
User user = new User ( );
user.setId (1371477785738010626L);
user.setName ("lucymary");
int count = userMapper.updateById (user);
System.out.println (count);
}
(2)自动填充:项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作
<1>填充步骤一:在实体类上加自动填充的注解
@TableField(fill = FieldFill.INSERT)
private Date createTime; // 数据库对应的字段(驼峰) create_time
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime; // 数据库对应的字段(驼峰) update_time
<2>填充步骤二:在实现对象处理接口后,重写进行配置自动填充
public class MyMetaObjectHandler implements MetaObjectHandler {
// 以mp执行添加操作后,这个方法执行
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName ("createTime", new Date ( ), metaObject);
this.setFieldValByName ("updateTime", new Date ( ), metaObject);
}
// 以mp执行修改操作后,这个方法执行
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
2、乐观锁
<1>主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
<2>乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
8、乐观锁实现具体步骤:
1、数据库创建字段,并在实体类对应的属性加上注解
@Version
private Integer version; // 数据库对应的字段: version
@TableField(value="version", fill = FieldFill.INSERT, update="%s+1")
private Integer version; // 数据库对应的字段: version
2、创建配置文件,并注册乐观锁插件
@Configuration
@MapperScan("com.kk.mybatispulstest.mapper")
public class MybatisPlusConfig {
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor ( );
}
}
9、查询
1、通过多个 id 批量查询
// 批量查询
@Test
public void testSelect1() {
List<User> users = userMapper.selectBatchIds (Arrays.asList (1, 2, 3));
System.out.println (users);
}
2、简单的条件查询:通过map封装查询条件
注意:map中的key对应数据库中的列名。如:数据库user_id,实体类是userId,这时map的key需要填写user_id
// 简单条件查询
@Test
public void testSelect2() {
HashMap<String, Object> columnMap = new HashMap<> ( );
columnMap.put ("name","jack");
columnMap.put ("age",20);
// 同时满足以上两个条件
List<User> users = userMapper.selectByMap (columnMap);
System.out.println (users );
}
10、分页
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
1、添加分页插件:MybatisPlusConfig 中
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor ( );
}
2、测试selectPage分页
//分页查询
@Test
public void testSelectPage() {
Page<User> page = new Page<> (1, 3);
Page<User> userPage = userMapper.selectPage (page, null);
// 返回对象得到分页所有数据
long pages = userPage.getPages ( ); // 总页数
long current = userPage.getCurrent ( ); // 当前页
List<User> records = userPage.getRecords ( ); // 查询数据集合
long total = userPage.getTotal ( ); // 总记录数
boolean hasNext = userPage.hasNext ( ); // 下一页
boolean hasPrevious = userPage.hasPrevious ( ); // 上一页
}
3、测试selectPage分页:返回结果集为 map
当指定了特定的查询列时,希望分页结果列表只返回被查询的列,而不是很多null值(值为 null 的 字段不会被封装进 map内 )
@Test
public void testSelectMapsPage() {
//Page不需要泛型
Page<Map<String, Object>> page = new Page<> (1, 5);
Page<Map<String, Object>> pageParam = userMapper.selectMapsPage (page, null);
List<Map<String, Object>> records = pageParam.getRecords ( );
records.forEach (System.out::println);
System.out.println (pageParam.getCurrent ( ));
System.out.println (pageParam.getPages ( ));
System.out.println (pageParam.getSize ( ));
System.out.println (pageParam.getTotal ( ));
System.out.println (pageParam.hasNext ( ));
System.out.println (pageParam.hasPrevious ( ));
}
11、删除
1、根据 id 删除
@Test
public void testDeleteById(){
int i = userMapper.deleteById (1371477785738010626L);
System.out.println (i );
}
2、根据 id 批量删除
@Test
public void testDeleteBatchIds() {
int result = userMapper.deleteBatchIds (Arrays.asList (8, 9, 10));
System.out.println (result);
}
3、简单条件删除
@Test
public void testDeleteByMap() {
HashMap<String, Object> map = new HashMap<> ( );
map.put ("name", "Helen");
map.put ("age", 18);
int result = userMapper.deleteByMap (map);
System.out.println (result);
}
12、逻辑删除
1、物理删除和逻辑删除
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
- 逻辑删除的使用场景:可以进行数据恢复,有关联数据,不便删除
2、具体实现步骤:
(1)数据库添加字段:
ALTER TABLE `user` ADD COLUMN `deleted` boolean DEFAULT false
(2)对应实体属性加注解
@TableLogic
private Integer deleted;
(3)配置(可选)
application.properties mp中默认的配置,如果不想改变一下可以不用写
mybatis-plus.global-config.db-config.logic-delete-value=1 #删除
mybatis-plus.global-config.db-config.logic-not-delete-value=0
(4)测试:
@Test
public void testLogicDelete() {
int result = userMapper.deleteById (1L);
User user = userMapper.selectById (1L);
System.out.println (result);
System.out.println ("查找删除后的"+user );// 输出结果:查找删除后的null
}
- 测试后发现,数据并没有被删除,deleted字段的值由0变成了1
- 测试后分析打印的sql语句,是一条update
- 注意:被删除前,数据的deleted 字段的值必须是 0,才能被选取出来执行逻辑删除的操作
(5)测试删除后的查询:MyBatis Plus中查询操作也会自动添加逻辑删除字段的判断
@Test
public void testLogicDeleteSelect() {
List<User> users = userMapper.selectList (null);
users.forEach (System.out::println);
}
13、条件构造器和常用接口
1、wapper介绍

Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
2、案例
(1)案例一:ge、gt、le、lt、isNull、isNotNull
@Test
public void testQuery() {
QueryWrapper<User> queryWrapper = new QueryWrapper<> ( );
queryWrapper.isNull ("name")// name 等于 null
.ge ("age",12) // 并且 age > 12
.isNotNull ("email");// 并且 email 不等于 null
int delete = userMapper.delete (queryWrapper);
System.out.println ("被删除的记录数:"+delete );
}
(2)案例二:eq、ne
注意:seletOne()返回的是一条实体记录,当出现多条时会报错
@Test
public void testSelectOne() {
QueryWrapper<User> queryWrapper = new QueryWrapper<> ( );
queryWrapper.eq ("name", "tom");
// 只能返回一条记录,多余一条则抛出异常
User user = userMapper.selectOne (queryWrapper);
System.out.println (user);
}
(3)案例三:between、notBetween,区间包含
@Test
public void testSelectCount() {
QueryWrapper<User> queryWrapper = new QueryWrapper<> ( );
queryWrapper.between ("age", 20, 30);// 年纪 20 到 30 岁
Integer count = userMapper.selectCount (queryWrapper);
List<User> users = userMapper.selectList (queryWrapper);
System.out.println ("符合个数:" + count);
System.out.println ("符合的集合:" + users);
}
(4)案例四: like、notLike、likeLeft、likeRight
selectMaps()返回Map集合列表,通常配合select()使用
@Test
public void testSelectMaps() {
QueryWrapper<User> qw = new QueryWrapper<> ( );
qw.select ("name", "age")// 指定返回的字段
.like ("name", "a")// 模糊搜索
.likeRight ("email", "4");// 模糊向右
// 以 map形式返回
List<Map<String, Object>> maps = userMapper.selectMaps (qw);
maps.forEach (System.out::println);
}
(5)案例五:orderBy、orderByDesc、orderByAsc
@Test
public void testSelectListOrderBy() {
QueryWrapper<User> queryWrapper = new QueryWrapper<> ( );
// 先根据年龄降序,再根据id
queryWrapper.orderByDesc ("age", "id");
List<User> users = userMapper.selectList (queryWrapper);
users.forEach (System.out::println);
}
3、查询方式
查询方式 | 说明 |
---|---|
select | 设置 SELECT 查询字段 |
where | WHERE 语句,拼接 + WHERE 条件 |
and | AND 语句拼接 + AND 字段=值 |
andNew | AND 语句,拼接 + AND (字段=值) |
or | OR 语句,拼接 + OR 字段=值 |
orNew | OR 语句,拼接 + OR (字段=值) |
eq | 等于= |
allEq | 基于 map 内容等于= |
ne | 不等于<> |
gt | 大于> |
ge | 大于等于>= |
lt | 小于< |
le | 小于等于<= |
like | 模糊查询 LIKE |
notLike | 模糊查询 NOT LIKE |
in | IN 查询 |
notIn | NOT IN 查询 |
isNull | NULL 值查询 |
isNotNull | IS NOT NULL |
groupBy | 分组 GROUP BY |
having | HAVING 关键词 |
orderBy | 排序 ORDER BY |
orderAsc | ASC 排序 ORDER BY |
orderDesc | DESC 排序 ORDER BY |
exists | EXISTS 条件语句 |
notExists | NOT EXISTS 条件语句 |
between | BETWEEN 条件语句 |
notBetween | NOT BETWEEN 条件语句 |
addFilter | 自由拼接 SQL |
last | 拼接在最后,例如:last(“LIMIT 1”) |
参考:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/89482201
网友评论