mybatis-plus
快速开始
- 官方文档
- 导入相关依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
最好不要和 mybatis 的依赖一起引入,防止报错
- 配置数据库
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8
# mysql8 之前是不需要设置时区的
username: root
password: 123456
-
不需要再写xml文件做mapper映射了
- 现在只需要
- pojo类
- mapper类 extends BaseMapper<对应泛型>
- 现在只需要
-
要在MybatisPlusConfig类上配置扫描包的mapper
@MapperScan("com.example.demo3.mapper") //扫描mapper文件夹
配置日志
- 所有的sql现在是不可见的,如果要看它是怎么执行的,就需要看日志
# 配置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
CRUD扩展
数据库插入id的默认值
-
雪花算法---默认生成全局唯一的id
默认 ID_WORKER 全局唯一id
雪花算法是Twitter开源的分布式ID算法,用于生成唯一的Long型id
-
如果需要配置主键自增
- 实体类字段上
@TableId(type = IdType.AUTO)
- 数据库字段也要设置成自增,不然会报错
自动填充
- 创建时间、修改时间都是自动化完成的,不希望手动创建
- 阿里巴巴开发手册:所有的数据库都需要包含表:gmt_create、gmt_modified,而且需要自动化
- 方式一:数据库级别(工作中不允许你更改数据库)
- 在表中新增字段 create_time,update_time
- 创建数据库的时候默认设置为 CURRENT_TIMESTAMP
- 在进行插入操作、更新操作的时候会自动更新这两个字段
- 方式二:代码级别
- 不设置默认值和更新
- 需要自己编写填充逻辑(mybatis-plus官方文档有提供)
- 在实体类字段上加上注解 @TableField(fill = FieldFIll.INSERT) 在插入的时候填充
- @TableField(fill = FieldFIll.UPDATE) 在更新的时候填充
乐观锁、悲观锁
-
面试过程中进场被提起
-
乐观锁:总是认为不会出现问题,无论干什么都不上锁,出了问题再更新值测试
-
悲观锁:总是认为会出现问题,无论干什么都上锁,之后再去操作
-
乐观锁实现方式:
- 取出记录的时候,获取当前version
- 更新时带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,酒更新失败
乐观锁:1、先查询、获得版本号 version = 1
-- 线程A
update user set name = "kuangshen",version = version + 1
where id = 2 and version = 1
-- 线程B 抢先完成,version = 2,会导致 A 修改失败
update user set name = "kuangshen",version = version + 1
where id = 2 and version = 1
实现乐观锁
- 添加version字段,默认值为1
- 对应实体类添加version
- @Version注解,代表这个字段是一个乐观锁
- 注册组件
- 写一个config,如MybatisPlusConfig
- @Configuration声明为配置类
- @EnableTransactionManagement事务管理辅助
- 在config类中配置乐观锁插件
@MapperScan("com.example.demo3.mapper") //扫描mapper文件夹
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
查询操作
- 例子
public void selectOne(){
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
//多id查询
public void selectByBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
//map查询,复杂的一般用Wrapper封装而不是map
public void testSelect(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","zhangsan");
map.put("age",3);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分页查询
- 配置拦截器组件 (config文件中)
@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);
}
- 接受前端参数、分页查询
public Page testPage(int pageNum,int pageSize){
Page page = userMapper.selectPage(new Page(pageNum, pageSize), null);
return page;
}
删除
- 与查询类似
逻辑删除
- 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
- 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。
物理删除:从数据库中直接移除
逻辑删除:数据库中不移除,而是通过一个变量来让该数据失效 delete 0 -> 1
-
类似于回收站
-
使用方式
- 数据库中增加 delete 字段
- 实体类中添加响应属性并加上注解
@TableLogic
private Integer delete;
- 配置yml文件
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
- 应用逻辑删除过后删除就相当于更新 delete = 1
- 之后查询的时候会自动过滤被逻辑删除的字段,但依然储存在数据库中
性能分析插件
- 用于检测慢sql的存在
- 已经被移除了,建议使用第三方插件进行sql打印
条件构造器
- 可以替代一些复杂的sql
- 一些例子
- 更多操作
//Wrapper查询的一些运用
public void WrapperTest1(){
//查询名字不为空
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name") //name 不为空
.isNotNull("email") //email 不为空
.ge("age",12); //年龄 ge 12
userMapper.selectList(wrapper).forEach(System.out::println);
}
public void WrapperTest2(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","zhang");
System.out.println(userMapper.selectOne(wrapper));
}
//20 ~ 30 之间的人数查询
public void WrapperTest3() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",20,30);
userMapper.selectCount(wrapper);
}
//模糊查询
public void WrapperTest4(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name","zhang")
.likeRight("email","t") //t开头的查询
.likeLeft("email","com"); //com结尾的查询
userMapper.selectList(wrapper).forEach(System.out::println);
}
//sql语句子查询
public void WrapperTest5(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id","select id from user where id < 3");
userMapper.selectObjs(wrapper).forEach(System.out::println);
}
//通过id进行排序
public void WrapperTest6(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
userMapper.selectList(wrapper).forEach(System.out::println);
}
代码自动生成器
- 添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.0</version>
</dependency>