爬梯:MyBatis-Plus全解析
建议搭配官网一起学习,MyBatis Plus是国人开发的,官网教程还是很通俗易懂的:https://mybatis.plus
MyBatis-Plus
MyBatis-Plus全面学习与应用
1、Hello MyBatis-Plus
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)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'aaa@qq.com'),
(2, 'Jack', 20, 'aaa@qq.com'),
(3, 'Tom', 28, 'aaa@qq.com'),
(4, 'Sandy', 21, 'aaa@qq.com'),
(5, 'Billie', 24, 'aaa@qq.com');
2. 创建SpringBoot项目,导入相应jar包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
3. 编写Dao
/**
* 继承 mybatis-plus 的Mapper
* 基本的CRUD已经全部写完
* @author: stone
* @create: 2020-09-03 00:04
*/
@Repository
public interface ISmartUserDao extends BaseMapper<SmartUser> {
}
4. 测试运行
@Autowired
ISmartUserDao smartUserDao;
@Test
void contextLoads() {
List<SmartUser> smartUsers = smartUserDao.selectList(null);
smartUsers.forEach(System.out::println);
}
console
配置日志
让sql可见
使用控制台输出
# 日志配置
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
console
至此入门结束。
2、主键生成策略
@Test
void testInsert(){
SmartUser smartUser = new SmartUser();
smartUser.setName("石似心");
smartUser.setAge(3);
smartUser.setEmail("aaa@qq.com");
// smartUser.setId();
System.out.println(smartUserDao.insert(smartUser));
System.out.println(smartUser);
}
console
自动添加了ID
ID主键生成策略
主键注解:@TableId
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface TableId {
String value() default "";
IdType type() default IdType.NONE;
}
public enum IdType {
AUTO(0), // 数据库ID自增
NONE(1), // 未设置主键
INPUT(2), // 手动输入
ID_WORKER(3), // 默认的全局唯一ID
UUID(4), // 全局唯一UUID
ID_WORKER_STR(5); // ID_WORKER 字符串表示法
private int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
AUTO
@TableId(type = IdType.AUTO)
这个auto的意思是使用数据库表的自增规则,+1,所以需要配合地去把数据库表ID设置为自增列,否则会报错~
ID_WORKER 默认主键生成策略,全局唯一
@TableId(type = IdType.ID_WORKER)
雪花算法 64位
分布式系统唯一ID,Twitter的snowflake,开源的分布式ID生成算法,结果是一个long类型的ID:
1、使用41bit作为毫秒数;
2、10bit作为机器的ID(5个bit是数据中心:北京、香港、西雅图…,5个bit是机器的ID);
3、12bit作为毫秒内的流水号(每个节点在每毫秒内可以生成4086个ID);
4、最有一个符号永远是0。
参考代码:https://github.com/twitter/snowflake
3、自动填充处理
@Test
void testUpdate(){
SmartUser smartUser = new SmartUser();
smartUser.setId(8l);
smartUser.setName("周杰伦");
smartUser.setAge(10);
System.out.println(smartUserDao.updateById(smartUser));
}
console
sql由mybatis plus动态拼接
alibaba开发手册:所有的数据库表都有 gmt_create、gmt_modified 这两个字段,而且需要自动化。
自动填充字段
1、数据库级别(企业都不会这么干)
2、代码级别
首先看到字段注解 @TableField
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface TableField {
String value() default "";
String el() default "";
boolean exist() default true;
String condition() default "";
String update() default "";
FieldStrategy strategy() default FieldStrategy.DEFAULT;
FieldFill fill() default FieldFill.DEFAULT;
boolean select() default true;
}
其中有个 FieldFill 字段填充对象,就是他了!
源码: 这里指的是,在进行什么类型的操作时,才执行fill
public enum FieldFill {
DEFAULT, // 默认,不处理
INSERT,
UPDATE,
INSERT_UPDATE;
private FieldFill() {
}
}
修改实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SmartUser {
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private int age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
填充什么东西咧,这里mybatisplus还没智能到去判断类型,所以需要写一个处理类,告诉他填充什么内容。
handler
/**
* 自动填充数据处理类
* @author: stone
* @create: 2020-09-04 00:45
*/
@Slf4j
@Component
public class MyMetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("insertFill is action ...");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("updateFill is action ...");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
执行插入:自动生成时间
执行更新:自动填充更新时间
4、数据乐观锁
给数据添加上乐观锁,既版本号控制;
主要适用场景
意图:
当要更新一条记录的时候,希望这条记录没有被别人更新
1、首先要在数据库表上加上version字段;
2、更新实体类
@Version
private int version;
3、添加配置类,配置乐观锁
/**
* @author: stone
* @create: 2020-09-04 22:17
*/
@MapperScan("com.ssx.studymybatisplus.dao")
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
//注册乐观锁
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
4、代码测试~
/**
* 测试乐观锁,模拟插队
* @throws InterruptedException
*/
@Test
void testOptimisticLock() throws InterruptedException {
// smartUser1
SmartUser smartUser1 = smartUserDao.selectById(1l);
smartUser1.setName("差不多先生");
// smartUser2
SmartUser smartUser2 = smartUserDao.selectById(1l);
smartUser2.setName("不用去猜");
// smartUser2 插队先操作了数据库
System.out.println("smartUser2 updated => "+smartUserDao.updateById(smartUser2));
TimeUnit.SECONDS.sleep(1);
System.out.println("smartUser1 updated => "+smartUserDao.updateById(smartUser1));
}
console
如果仍希望update smartUser1,可以使用自旋锁,再次去获取版本号更新(递归锁)
5、分页查询
-
sql关键字limit
-
pageHelper分页插件
-
MyBatisPlus内置分页工具
1、从官网可以获取到配置分页拦截器的代码
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
里面可以配置很多信息:
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
//paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
2、使用分页的方法查询
@Test
void testPage(){
// 当前页码 1 ,单页的记录数 3
Page<SmartUser> page = new Page<>(1,3);
IPage<SmartUser> smartUserIPage = smartUserDao.selectPage(page, null);
List<SmartUser> records = smartUserIPage.getRecords();
records.forEach(System.out::println);
}
console
查询方法中的 page 对象,会在查询之后得到回写:
可以获取当前页的相关信息
6、逻辑删除
当用户进行删除操作之后,将数据的状态改为“删除”,但并不会真正的把数据从数据库中删除,进而保护了数据,增强安全性。
学习三步走~
1、数据库加字段
deleted int(1) 默认0
行规~ 0:否;1:是;
2、更新实体类
@TableLogic
private int deleted;
3、添加配置~
application.properties
# 逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
注册逻辑删除拦截器
@Bean
public LogicSqlInjector logicSqlInjector(){
return new LogicSqlInjector();
}
4、代码测试
@Test
void testLogicDelete(){
//执行删除
smartUserDao.deleteById(2l);
//查询删除的数据
System.out.println(smartUserDao.selectById(2l));
}
console
可以看到,执行delete实则执行的是update sql,
然后执行select自动添加了deleted=0操作。
7、性能分析插件
可以查看sql的执行时间,可以格式化sql代码,可以设置sql执行超过多少时间则抛出异常…
但是官网说3.x后的版本移除次插件,建议使用第三方插件…
不过经测试,3.0.2版本还是可以用,代码还没删除也没画横线…
配置拦截器
/**
* SQL执行效率插件
*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setFormat(true);
performanceInterceptor.setMaxTime(1000);
return performanceInterceptor;
}
代码测试
smartUserDao.selectList(null);
console
8、条件构造器
官方API:https://mybatis.plus/guide/wrapper.html#abstractwrapper
操作
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq()
…
拼装查询条件进行查询
由于工作中常用,就不写测试代码了!
9、代码生成器
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
官方API:https://mybatis.plus/guide/generator.html#%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B
官网有默认的配置,直接拷下来改~