欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

爬梯:MyBatis-Plus全解析

程序员文章站 2022-07-13 08:36:08
...

学习资源整理自:B站《狂神说》

建议搭配官网一起学习,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

爬梯:MyBatis-Plus全解析

配置日志

让sql可见

使用控制台输出

# 日志配置
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

console

爬梯:MyBatis-Plus全解析

至此入门结束。

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

爬梯:MyBatis-Plus全解析

自动添加了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

爬梯:MyBatis-Plus全解析

sql由mybatis plus动态拼接

alibaba开发手册:所有的数据库表都有 gmt_create、gmt_modified 这两个字段,而且需要自动化。

自动填充字段

1、数据库级别(企业都不会这么干)

爬梯:MyBatis-Plus全解析

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);
    }
}

执行插入:自动生成时间

爬梯:MyBatis-Plus全解析

执行更新:自动填充更新时间

爬梯:MyBatis-Plus全解析

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

爬梯:MyBatis-Plus全解析

如果仍希望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

爬梯:MyBatis-Plus全解析

查询方法中的 page 对象,会在查询之后得到回写:

爬梯:MyBatis-Plus全解析

可以获取当前页的相关信息

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

爬梯:MyBatis-Plus全解析

可以看到,执行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

爬梯:MyBatis-Plus全解析

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

官网有默认的配置,直接拷下来改~

相关标签: java mybatis