欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

【MyBatisPlus3.5.1】2、CRUD扩展:自动填充、乐观锁、分页查询、逻辑删除【SpringBoot环境】

时间:2023-08-17
1、Insert 1)插入测试

@Testvoid testInsert(){ User user = new User(); user.setName("tuwer"); user.setAge(8); user.setEmail("abc@qq.com"); // 会自动生成id int res = userMapper.insert(user); System.out.println(res); System.out.println(user);}

2)主键策略

@TableId

描述:主键注解使用位置:实体类主键字段

@documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})public @interface TableId { String value() default ""; IdType type() default IdType.NONE;}

IdType 枚举类

public enum IdType { AUTO(0), NONE(1), INPUT(2), ASSIGN_ID(3), ASSIGN_UUID(4); private final int key; IdType(int key) { this.key = key; }}

雪花(snowflake)算法

snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心(北京、香港···),5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

2、Update

@Testvoid testUpdate(){ User user = new User(); user.setId(8L); user.setName("tuwer测试"); user.setAge(28); user.setEmail("abc@qq.com"); // 虽然方法是ById,但参数是类对象user int i = userMapper.updateById(user); System.out.println(i);}


3、自动填充

创建时间、更改时间! 这些操作一般都是自动化完成,不需要手动更新

阿里巴巴开发手册︰几乎所有的表都要配置 gmt_create、gmt_modified !而且需要自动化

1)方式一:数据库级别

实际开发中不允许修改数据库级别

修改数据库:添加 gmt_create 和 gmt_modified 字段

alter table user add gmt_create datetime default CURRENT_TIMESTAMP null comment '创建时间';alter table user add gmt_modified datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间';

修改实体类

驼峰命名:gmtCreate 对应于数据库中的 gmt_create

日期类型可以用 Date 和 LocalDateTime,建议用 LocalDateTime

private Date gmtCreate;private LocalDateTime gmtModified;

2)方式二:代码级别

删除数据库级别中的操作:默认值、更新

实体类字段属性上增加注解

// 插入时填充@TableField(fill = FieldFill.INSERT)private Date gmtCreate;// 插入、更新时填充@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime gmtModified;

填充处理器

填充处理器 MymetaObjectHandler 在 Spring Boot 中需要声明 @Component 或 @Bean 注入

@Slf4j@Componentpublic class MymetaObjectHandler implements metaObjectHandler { @Override public void insertFill(metaObject metaObject) { log.info("开始插入时填充..."); this.strictInsertFill(metaObject, "gmtCreate", Date.class, new Date()); this.strictInsertFill(metaObject, "gmtModified", LocalDateTime.class, LocalDateTime.now()); } @Override public void updateFill(metaObject metaObject) { log.info("开始插入更新时填充..."); this.strictUpdateFill(metaObject, "gmtModified", LocalDateTime.class, LocalDateTime.now()); }}

测试

插入测试

更新测试


4、乐观锁

乐观锁:十分乐观,总是认为不会出现问题;无论干什么都不上锁!如果出现问题,再次更新值测试

悲观锁:十分悲观,总是认为会出现问题;无论干什么都会上锁!再去操作!

乐观锁实现方式:

当要更新一条记录的时候,希望这条记录没有被别人更新

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

1)修改数据库

添加 version 字段

2)修改实体类

添加 version 属性,并添加 @Version 注解

@Versionprivate Integer version;

3)注册乐观锁组件

@Configuration@MapperScan("com.tuwer.mapper")public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; }}

4)测试

单线程

@Testpublic void testOptimisticLocker1(){ //1、查询用户信息 User user = userMapper.selectById(8L); //2、修改用户信息 user.setAge(18); user.setEmail("111@qq.com"); //3、执行更新操作 userMapper.updateById(user);}

模拟多线程

@Testpublic void testOptimisticLocker2(){ // 线程1 User user1 = userMapper.selectById(8L); user1.setAge(1); user1.setEmail("222@qq.com"); // 模拟另外一个线程执行了插队操作 User user2 = userMapper.selectById(8L); user2.setAge(2); user2.setEmail("333@qq.com"); userMapper.updateById(user2); // 自旋锁来多次尝试提交! userMapper.updateById(user1);//如果没有乐观锁就会覆盖插队线程的值}

5、Select 1)通过id查询单个用户

@Testpublic void testSelectById(){ User user = userMapper.selectById(8L); System.out.println(user);}

2)通过id查询多个用户

@Testpublic void testSelectBatchIds(){ List users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 5L)); users.forEach(System.out::println);}

3)条件查询 通过map封装

@Testpublic void testSelectByMap() { HashMap map = new HashMap<>(); map.put("name", "tuwer"); map.put("age", 2); List users = userMapper.selectByMap(map);}

4)分页查询

selectPage()

// 参数1:IPage对象// 参数2:Wrapper 条件构造器// 返回:IPage对象;把结果封装进参数1的IPage对象

> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper);

Page 类

Page 类实现了 IPage 接口默认值:每页显示条数 10,当前页 1

public class Page implements IPage { // ... protected long size = 10; protected long current = 1; // ...}

构造器

注册分页拦截器

@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); // 乐观锁 ... // 分页 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return mybatisPlusInterceptor;}

查询

@Testpublic void testSelectPage(){ // 按Page默认值查询 Page page = new Page<>(); userMapper.selectPage(page, null); page.getRecords().forEach(System.out::println);}

@Testpublic void testSelectPage(){ // 查第2页,3条记录 Page page = new Page<>(2,3); userMapper.selectPage(page, null); page.getRecords().forEach(System.out::println);}

6、Delete 1)物理删除

从数据库中直接删除

2)逻辑删除

在数据库中没有被删除,而是通过一个变量来使它失效! deleted=0 ==> deleted=1逻辑删除是为了 方便数据恢复 和 保护数据本身价值 等等的一种方案,但实际就是删除删除: 转变为 更新

修改数据库:增加 deleted 字段

alter table user add deleted tinyint default 0 not null comment '逻辑删除';

配置

mybatis-plus: global-config: db-config: #logic-delete-field: deleted # 逻辑删除的实体字段名(配置后可以忽略不配置实体类) logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

修改实体类:增加 deleted 属性,并添加 @TableLogic 注解

@TableLogic // 如果配置了logic-delete-field: deleted,此处可以省略 @TableLogicprivate Integer deleted;

删除

@Testpublic void testDelete(){ userMapper.deleteById(8L);}

配置logic-delete-field: deleted,省略 @TableLogic


删除后再查询

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。