Mybatis-Plus使用(二)操作语法
1. 插入测试及雪花算法
CRUD扩展
Insert插入
@Test
void testInsert(){
    User user = new User();
    user.setName("levnli").setAge(23).setEmail("levnliservice@126.com");
    // 自动生成id
    int result = userMapper.insert(user);
    // 受影响的行数
    System.out.println(result);
    // 发现 id 会自动回填
    System.out.println(user);
}
数据库插入的id的默认值为:全局唯一的
主键生成策略:雪花算法
- 
id自增策略是:ID_WORKER 
- 
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID,其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一 
2. 不同主键策略测试
/**
 * 数据库ID自增
 */
AUTO(0),
/**
 * 该类型为未设置主键类型
 */
NONE(1),
/**
 * 用户输入ID
 * 该类型可以通过自己注册自动填充插件进行填充
 */
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
 * 全局唯一ID (idWorker)
 */
ID_WORKER(3),
/**
 * 全局唯一ID (UUID)
 */
UUID(4),
/**
 * 字符串全局唯一ID (idWorker 的字符串表示)
 */
ID_WORKER_STR(5);
- 如果想选用策略为:AUTO
- 实体类字段上添加@TableId(type = IdType.AUTO)
- 数据库字段一定要是自增!
 
- 实体类字段上添加
- 再次测试插入
3. 更新操作
@Test
void testUpdate(){
    User user = new User().setId(1336837066142076930L).setName("test");
    int i = userMapper.updateById(user);
    System.out.println(i);
}
- 所有的sql都是自动拼接,动态配置的
自动装填
- 创建时间、修改时间!这些操作都是自动化完成的,不希望手动更新
- 所有的数据库表:gmt_create、gmt_modified,几乎所以的表都要配置上,而且需要自动填充
4. 自动填充处理
方式一:数据库级别(工作中不允许修改数据库)
- 
在表中新增字段create_time,update_time ALTER TABLE `mybatis_plus`.`user` ADD COLUMN `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' AFTER `email`, ADD COLUMN `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' AFTER `create_time`;
- 
再次测试插入方法,先把实体类同步 - 
private Date createTime; private Date updateTime;
 
- 
- 
再次更新查看即可 
方式二:代码级别
- 
删除数据库的默认值、更新操作! - 去掉时间配置
- ALTER TABLE mybatis_plus.user
 MODIFY COLUMNcreate_timedatetime(0) NULL COMMENT '创建时间' AFTERemail,
 MODIFY COLUMNupdate_timedatetime(0) NOT NULL COMMENT '更新时间' AFTERcreate_time;
 
- 
实体类的字段属性上需要增加注解 - 
// 字段添加填充内容 @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
 
- 
- 
编写处理器,来处理这个注解即可 @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { /** * 插入时的填充策略 * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill...."); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } /** * 更新时的填充策略 * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { log.info("start updateTime fill...."); this.setFieldValByName("updateTime",new Date(),metaObject); } }
- 
测试插入、更新 - 观察时间即可
 
5. 乐观锁处理详解
- 
在面试过程中,经常被问到乐观锁、悲观锁 
- 
乐观锁 - 十分乐观,不会认为出现问题
- 无论干什么都不会上锁
- 如果出现了问题,再次更新值测试
- version、new version
 
- 
悲观锁 - 十分悲观,总是认为都会出现问题
- 无论干什么都会上锁!再去操作
 
- 
主要讲解乐观锁机制 
- 
乐观锁实现方式: - 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
 乐观锁:先查询,获得版本号version = 1 -- A线程 update user set name = "test" , version = version + 1 where id = 2 and version = 1 -- B线程 update user set name = "test" , version = version + 1 where id = 2 and version = 1 结果B线程抢先完成,这时候version = 2,导致A线程修改失败
测试一下MP的乐观锁插件
- 
给数据库中添加version字段 - ALTER TABLE mybatis_plus.user
 MODIFY COLUMNversionint(10) NULL DEFAULT 1 COMMENT '乐观锁' AFTERupdate_time
 ADD COLUMNversionint(10) NULL COMMENT '乐观锁' AFTERupdate_time;
 
- ALTER TABLE 
- 
实体类添加对应的字段 - 
/** * 乐观锁version注解 */ @Version private Integer version;
 
- 
- 
注册组件 @EnableTransactionManagement @MapperScan("com.example.mapper") @Configuration public class MyBatisPlusConfig { // 注册乐观锁插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } }
- 
测试一下 @Test void testOptimisticLocker(){ // 查询用户信息 User user = userMapper.selectById(6L); // 修改用户信息 user.setEmail("123@qq.com"); // 执行更新 userMapper.updateById(user); } @Test void testOptimisticLockerThread(){ // 模拟乐观锁,多线程并发 // 线程1 User user = userMapper.selectById(6L); user.setEmail("111@qq.com"); // 线程2,抢先提交 User user2 = userMapper.selectById(6L); user2.setEmail("222@qq.com"); userMapper.updateById(user2); userMapper.updateById(user); }
6. 查询操作
- 批量查询和条件查询
/**
 * 测试批量查询
 */
@Test
void testSelectByIds(){
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));
    users.forEach(System.out::println);
}
/**
 * 条件查询之一使用 map
 */
@Test
void selectByMap(){
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","levnli");
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}
7. 分页查询实现
- 分页查询在网站使用十分之多!
- 原始的limit进行分页
- pageHelper第三方插件
- MP其实也内置了分页插件
 
如何使用
- 
配置拦截器组件即可 - 
// 分页插件 @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }
 
- 
- 
直接使用Page对象即可 - 
@Test void testPage(){ // 参数:当前页、页面大小 Page<User> page = new Page<>(2,5); userMapper.selectPage(page,null); // 打印查询结果 page.getRecords().forEach(System.out::println); // 当前表总共条数 System.out.println(page.getTotal()); }
 
- 
8. 删除操作
- 
根据ID删除记录 /** * 通过ID删除 */ @Test void testDeleteById(){ userMapper.deleteById(1336837066142076931L); }
- 
根据ID批量删除 /** * 通过ID批量删除 */ @Test void testDeleteBatchIds(){ userMapper.deleteBatchIds(Arrays.asList(1336837066142076931L)); }
- 
根据条件删除 /** * 通过条件删除 */ @Test void testDeleteMap(){ HashMap<String, Object> map = new HashMap<>(); map.put("name","test2"); userMapper.deleteByMap(map); }
9. 逻辑删除
- 物理删除:从数据库中直接移除
- 逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效!
- deleted = 0 -> deleted = 1
 
- 管理员可以查看被删除的记录!防止数据的丢失,类似于回收站
测试一下:
- 
在数据报中增加一个 deleted字段ALTER TABLE `mybatis_plus`.`user` ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '删除标志位' AFTER `version`;
- 
在实体类上添加字段 /** * 逻辑删除 */ @TableLogic private Integer deleted;
- 
添加插件 // 逻辑删除插件 @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); }
- 
配置逻辑删除 mybatis-plus: global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0
10. 性能分析插件
开发中,会遇到慢sql
MP也提供性能分析插件,如果超过这个时间就是停止运行
- 
导入插件 // SQL执行效率插件 @Bean @Profile("dev") public PerformanceInterceptor performanceInterceptor(){ PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); // sql最大执行时间,超过不执行 performanceInterceptor.setMaxTime(100); // 输出sql格式化 performanceInterceptor.setFormat(true); return performanceInterceptor; }
- 
修改application.yml spring: profiles: active: dev
- 
测试使用 - 执行任何一个方法
 
- 感谢你赐予我前进的力量
                        
                        
                            
赞赏者名单
                            因为你们的支持让我意识到写文章的价值🙏
                        
                    
            本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 木子李
        
     评论
            
                匿名评论
                隐私政策
            
            
                你无需删除空行,直接评论以获取最佳展示效果
            
         
            
        

 
                         
                         
                         
                         
                 
             
            