Mybatis-plus简述
对Mybatis的扩展,不修改,增加功能,为简化而生!
官方文档:https://baomidou.com/
快速入门
- 导入依赖
- 研究依赖如何配置
- 代码编写
- 提高扩展技术能力
步骤
-
创建数据库test_mybatisplus
-
创建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) ); 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'); -- version 乐观锁 deleted 逻辑删除-
创建SpringBoot工程,导入依赖
<!-- 开源的Start --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>说明:不要同时导入mybatis和mybatis plus,可能会冲突
-
配置yml文件 ( 连接数据库 )
#mysql 8 spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/test_mybatisplus?userSSL=false&userUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 driver-class-name: com.mysql.cj.jdbc.Driver-
配置环境
-
pojo
package com.yang.po; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { Long id; String name; Integer age; String email; } -
mapper
package com.yang.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.yang.po.User; import org.springframework.stereotype.Repository; import java.util.List; // BaseMapper 封装好了对应的方法 @Repository // 注解表示dao层 public interface UserMapper extends BaseMapper<User> { // 所有CRUD操作都编写好了 // 跟JPA很像 // 不需要配置xml文件 } -
主启动器
package com.yang; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // 扫描mapper文件夹 @MapperScan("com.yang.mapper") @SpringBootApplication public class SpringbootTestApplication { public static void main(String[] args) { SpringApplication.run(SpringbootTestApplication.class, args); } } -
测试
package com.yang; import com.yang.mapper.UserMapper; import com.yang.po.User; import org.junit.jupiter.api.Test; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @SpringBootTest class SpringbootTestApplicationTests { @Autowired UserMapper userMapper; @Test void contextLoads() { // 参数是一个wrapper条件构造器 // 查询所有用户 List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }
-
-
-
配置日志
现在所有sql语句都是不可见的,如果希望看见,就需要看配置日志
在yml文件中添加
# 配置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
CRUD 扩展
插入操作
-
插入测试
// 测试插入 @Test public void testInsert(){ // 自动生成id // 自动回填id User user = new User(); user.setName("卓亮"); user.setAge(18); user.setEmail("2182433986@qq.com"); int insert = userMapper.insert(user); System.out.println(insert); System.out.println(user); }结果会自动填入一个长串id
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ss6rjby5-1662359204057)(C:\Users\zhuima\AppData\Roaming\Typora\typora-user-images\image-20210409223328203.png)]
数据库插入id的默认值为:全局唯一id
主键生成策略
分布式系统唯一id生成: https://www.cnblogs.com/haoxinyue/p/5208136.html
雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake,可以保证全球唯一!
主键自增
需要配置主键自增加上:@TableId(type = IdType.AUTO)
数据库字段也要是自增的!
IdType 源码解释
public enum IdType {
AUTO(0), // 数据库id自增
NONE(1), // 未设置主键
INPUT(2), // 手动输入
ID_WORKER(3), // 默认全局唯一id
UUID(4), // uuid 全球唯一id
ID_WORKER_STR(5); // 字符串表示法
}
更新操作
测试更新
// 测试更新
@Test
public void testUpdate(){
User user = new User();
user.setName("卓亮");
user.setAge(20);
user.setEmail("2182433986@qq.com");
// 参数是一个user对象
int i = userMapper.updateById(user);
System.out.println(i);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-REQIwwFi-1662359204059)(C:\Users\zhuima\AppData\Roaming\Typora\typora-user-images\image-20210410101545742.png)]
所有sql都是动态自动创建的!
自动填充
创建时间、修改时间!这些操作一般都是自动化完成的,我们不希望手动更新!
阿里巴巴开发手册:所有数据库表:gmt_create、gmt_modified几乎所有表要配置,而且需要自动化
方式一:数据库级别(工作中不建议)
- 在表中新增字段 gmt_create、gmt_modified
方式二:代码级别
- 删除数据库的默认值

-
实体类上增加注解
// 字段添加填充内容 @TableField( fill = FieldFill.INSERT) Date createTime; @TableField( fill = FieldFill.INSERT_UPDATE) Date updateTime; -
编写处理器来处理注解
新建handler包,在包下创建MymetaObjectHandler
package com.yang.handler; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; @Slf4j @Component // 一定不要忘记把处理器加到IOC容器中 public class MymetaObjectHandler implements MetaObjectHandler { // 插入时的填充策略 @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill......"); // 参数 tring fieldName, Object fieldVal, MetaObject metaObject this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } // 更新时的填充策略 @Override public void updateFill(MetaObject metaObject) { log.info("start insert fill......"); this.setFieldValByName("updateTime",new Date(),metaObject); } } -
测试插入
-
测试更新、观察时间
乐观锁
乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
悲观锁 主要用于保护数据的完整性。当多个事务并发执行时,某个事务对数据应用了锁,则其他事务只能等该事务执行完了,才能进行对该数据进行修改操作
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
测试MybatisPlus乐观锁插件
-
新建version字段,设置默认值为1
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vuxUhzVn-1662359204060)(C:\Users\zhuima\AppData\Roaming\Typora\typora-user-images\image-20210410130941644.png)]](https://i-blog.csdnimg.cn/blog_migrate/a775f4c28eb54eb969655c20821bdbea.png)
-
实体类上新增相应字段
// 乐观锁注解 @Version Integer version; -
注册组件,创建config包,包下创建MybatisPlusConfig.java
// 注册乐观锁插件 public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } -
测试乐观锁
// 测试乐观锁成功 @Test public void testOptimisticLocker(){ // 查询 User user = userMapper.selectById(1L); // 修改 user.setAge(100); user.setEmail("xxs@email.com"); // 更新 userMapper.updateById(user); } // 测试乐观锁失败 @Test public void testOptimisticLocker2(){ // 线程1 User user = userMapper.selectById(1L); user.setAge(200); user.setEmail("x123s@email.com"); // 模拟插队 User user2 = userMapper.selectById(1L); user2.setAge(100); user2.setEmail("123s@email.com"); userMapper.updateById(user2); userMapper.updateById(user); }
查询操作
// 查询测试
@Test
public void testSelect(){
User user = userMapper.selectById(1L);
// 查询批量用户
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
System.out.println(users);
}
// 条件查询之一 map
@Test
public void testSelectByMap(){
HashMap<String, Object> map = new HashMap<>();
// 自定义查询
map.put("name","Jone");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分页查询
分页查询网站使用太多了~!
-
原始 limit 分页
-
pageHelper 第三方插件
-
MP 内置分页插件 (牛逼~)
使用
-
配置拦截器 (MybatisPlusConfig.java)最新版
// 注册分页插件 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); } -
查询测试
// 测试分页查询 @Test public void testPage() { // 参数一 当前页 // 参数二 页面大小 Page<User> page = new Page<>(1,5); userMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
删除操作
基本的删除操作
// 删除测试
@Test
public void testDelete() {
userMapper.deleteById(1380745381188530177L);
}
// id 批量删除
@Test
public void testDeleteBatchId() {
userMapper.deleteBatchIds(Arrays.asList(1380745381188530177L,1380528520026939394L));
}
// 通过 map 删除
@Test
public void testDeleteByMap() {
HashMap<String,Object> map = new HashMap<>();
map.put("name","卓亮");
userMapper.deleteByMap(map);
}
下面介绍重要的逻辑删除!
逻辑删除
物理删除:从数据库直接删除
逻辑删除:没有真正被删除,而是通过一个变量让他失效 delete=0 => delete=1
管理员可以查看被删除的记录,防止数据的丢失,类似于回收站
测试一下:
- 在数据库中添加 deleted 字段

-
实体类中增加属性
// 逻辑删除 @TableLogic Integer deleted; -
yml配置 (可以忽略)
# 逻辑删除配置(默认就有) mybatis-plus: configuration: global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0 -
测试删除
@Test public void testDelete() { userMapper.deleteById(1L); } // 本质上做的是更新操作,将deleted字段更新为 1
以上 CRUD 及其附属操作操作必须精通,且熟练掌握~!
性能分析插件
平时开发中,会遇到慢sql(即运行效率低的语句)
MP 提供了性能分析插件,如果查过这个时间就停止运行!
不过新版本启用了,哈哈
条件构造器
十分重要:Wrapper
写一些复杂的sql就可以用它代替
package com.yang;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yang.mapper.UserMapper;
import com.yang.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* Created by Joms on 2021/4/10
*/
@SpringBootTest
public class WrapperTest {
@Autowired
UserMapper userMapper;
@Test
void contextTest(){
// 查询name不为空的用户,并且邮箱不为空,年龄大于等于12
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
}
@Test
void test2(){
// 查询指定name,如果name重复,且用的selectOne方法会报错
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","Billie");
System.out.println(userMapper.selectOne(wrapper));
}
@Test
void test3(){
// 查询年龄在20-30之间的用户个数
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",20,30);
System.out.println(userMapper.selectCount(wrapper));
}
@Test
void test4(){
// 模糊查询
// ==> Preparing: SELECT id,name,age,email,deleted,version,create_time,update_time FROM user WHERE deleted=0 AND (name NOT LIKE ? AND email LIKE ?)
// ==> Parameters: %e%(String), t%(String)
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 左合右
wrapper
.notLike("name","e")
// right 左边加参数
.likeRight("email","t");
userMapper.selectList(wrapper).forEach(System.out::println);
}
@Test
void test5(){
// 通过id进行排序
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
userMapper.selectList(wrapper).forEach(System.out::println);
}
}
其余测试在:https://baomidou.com/guide/wrapper.html#notin 可以自行测试~
737

被折叠的 条评论
为什么被折叠?



