云倾万里

无人问津的港口,总是开满鲜花

0%

Mybatis-plus-Note

✍️

Mybatis-plus学习

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus -->
<!-- mybatis-plus 是自己开发,并非官方的! -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>

配置数据库信息

1
2
3
4
5
6
7
# 数据库连接配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: baibing123

配置日志

查看sql执行日志

1
2
3
4
# 配置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

CRUD扩展

数据库插入的id的默认值为:全局唯一id

雪花算法

snowflake是twitter开源的分布式ID生成算法,结果是一个long型的id

其核心思想是:使用64bit作为毫秒数,10bit作为机器id(5个bit是数据中心,5个bit是机器ID) 12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID) 最后一个是符号位 永远是0.可以保证几乎全球唯一

INSERT

1
2
3
4
5
6
7
8
9
@Test
public void TestInsert(){
User user = new User();
user.setName("Jhonny");
user.setAge(3);
user.setEmail("123@qq.com");
int result = userMapper.insert(user);
System.out.println(result);
}

UPDATE

所有的sql都是自动动态配置

自动填充

创建时间,修改时间,这个操作一遍都是自动化完成的。

  1. 删除数据库的默认值,更新操作(修改时间)

  2. 实体类字段属性上需要添加注解

    1
    2
    3
    4
    5
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
  3. 编写处理器来处理这个注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Slf4j
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {

    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
    log.info("start insert fill...");
    this.setFieldValByName("createTime",new Date(),metaObject);
    this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
    log.info("start update fill...");
    this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    }

乐观锁

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时,set version = new Version where version = oleVersion
  • 如果version不对, 就更新失败

MP添加乐观锁

  1. 数据库添加version字段

  2. 实体类加对应字段

    1
    2
    @Version//乐观锁version注解
    private Integer version;
  3. 注册组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //扫描mapper文件夹
    @MapperScan("cn.bybing.mapper")
    @EnableTransactionManagement//TX
    @Configuration//配置类
    public class MyBatisPlusConfig {
    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
    return new OptimisticLockerInterceptor();
    }
    }
  4. 测试代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    @Test
    //测试乐观锁成功
    public void testOptimisticLocker(){
    //1.查询用户信息
    User user = userMapper.selectById(1L);
    //2.修改用户信息
    user.setName("jhonny22");
    user.setEmail("jhonny22@163.com");
    //3.执行更新操作
    userMapper.updateById(user);
    }

    @Test
    //测试乐观锁失败,多线程下
    public void testOptimisticLocker2(){
    //线程1
    //1.查询用户信息
    User user = userMapper.selectById(1L);
    //2.修改用户信息
    user.setName("jhonny111");
    user.setEmail("jhonny111@163.com");

    //模拟另外一个线程执行了插队操作
    //1.查询用户信息
    User user2 = userMapper.selectById(1L);
    //2.修改用户信息
    user2.setName("jhonny222");
    user2.setEmail("jhonny222@163.com");
    //3.执行更新操作
    userMapper.updateById(user2);

    userMapper.updateById(user);
    }

查询操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//测试id查询
@Test
public void testSelecById(){
User user = userMapper.selectById(1l);
System.out.println(user);
}

//条件查询
@Test
public void testSelectByMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("age",24);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}

分页查询

  1. 在mp配置类中添加拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Bean
    public PaginationInterceptor paginationInterceptor() {
    PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
    // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
    // paginationInterceptor.setOverflow(false);
    // 设置最大单页限制数量,默认 500 条,-1 不受限制
    // paginationInterceptor.setLimit(500);
    // 开启 count 的 join 优化,只针对部分 left join
    paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
    return paginationInterceptor;
    }

    可以简写:
    //分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
    }

    测试:

    1
    2
    3
    4
    5
    6
    7
    8
    //测试分页查询
    @Test
    public void testPage(){
    // 参数1:当前页
    // 参数2:页面大小
    Page<User> page = new Page<>(1,5);
    IPage<User> userIPage = userMapper.selectPage(page, null);
    userIPage.getRecords().forEach(System.out::println);

删除操作

类似添加操作

逻辑删除

物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让它失效,deleted=0 => deleted=1

防止数据的丢失,类似回收站

测试:

  1. 在数据库中添加deleted字段

  2. 实体类中添加属性

    1
    2
    @TableLogic //逻辑删除
    private Integer deleted;
  3. 配置

    1
    2
    3
    4
    5
    //逻辑删除组件
    @Bean
    public ISqlInjector sqlInjector(){
    return new LogicSqlInjector();
    }

性能分析插件

在mp配置类中添加插件代码

1
2
3
4
5
6
7
8
9
//sql执行效率插件
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);//设置sql执行最大时间。如果超过了则不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}

条件构造器(Wrapper)

demo1:

1
2
3
4
5
6
7
8
9
@Test
void contextLoad(){
// 查询name不为空的用户,并且邮箱不为空,年龄大于等于12
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
}

demo2:

1
2
3
4
5
6
7
@Test
public void testWrapper(){
//查询指定名字
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "jhonny222");
System.out.println(userMapper.selectOne(wrapper));
}

模糊查询

1
2
3
4
5
6
7
8
9
10
@Test
public void testWrapper3(){
//查询年龄在20 - 30 岁之间的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.notLike("name","e")
// 左和右 likeRight:t% likeLeft:%t
.likeRight("email","t");
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}

代码自动生成器

👉​ https://baomidou.com/pages/779a6e/ 官方文档

Welcome to my other publishing channels