【MyBatis Plus】逻辑删除、分页、乐观锁的应用及讲解 | 您所在的位置:网站首页 › mybatis悲观锁 › 【MyBatis Plus】逻辑删除、分页、乐观锁的应用及讲解 |
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《MyBatis-Plus》。🎯🎯 👉点击这里,就可以查看我的主页啦!👇👇 Java方文山的个人主页 🎁如果感觉还不错的话请给我点赞吧!🎁🎁 💖期待你的加入,一起学习,一起进步!💖💖 虽然mybatis-plus提供了主键策略,但是它那个并不是很好用,我这里在网上寻找了一个“雪花ID”,觉得还不错于是覆盖了原有的主键策略,但这里还有一个缺陷,每次需要手动set设置,也是比较麻烦的,所以我们就会用到mybatis-plus的自定义ID生成器。 方法主键生成策略主键类型说明nextIdASSIGN_ID,ID_WORKER,ID_WORKER_STRLong,Integer,String支持自动转换为 String 类型,但数值类型不支持自动转换,需精准匹配,例如返回 Long,实体主键就不支持定义为 IntegernextUUIDASSIGN_UUID,UUIDString默认不含中划线的 UUID 生成官网提供了SpringBoot以下三种方式: 方式一:声明为 Bean 供 Spring 扫描注入 @Component public class CustomIdGenerator implements IdentifierGenerator { @Override public Long nextId(Object entity) { //可以将当前传入的class全类名来作为bizKey,或者提取参数来生成bizKey进行分布式Id调用生成. String bizKey = entity.getClass().getName(); //根据bizKey调用分布式ID生成 long id = ....; //返回生成的id值即可. return id; } }方式二:使用配置类 @Bean public IdentifierGenerator idGenerator() { return new CustomIdGenerator(); }方式三:通过 MybatisPlusPropertiesCustomizer 自定义 @Bean public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() { return plusProperties -> plusProperties.getGlobalConfig().setIdentifierGenerator(new CustomIdGenerator()); }我们使用第一种方式,但首先需要有雪花ID的依赖,随后修改其内容即可 com.github.yitter yitter-idgenerator 1.0.6 @Component public class CustomIdGenerator implements IdentifierGenerator { @Override public Long nextId(Object entity) { return YitIdHelper.nextId(); } }测试一下:
测试成功,说明当我们不满足于官方提供的主键策略时,也可根据这样的方式定义。 二、逻辑删除 2.1.什么是逻辑删除MyBatis-Plus中的逻辑删除(Logical Delete)是在数据库中进行虚拟删除,即实际删除数据时,并不会将数据从数据库中删除,而是通过一个标记来记录其已被删除。这种删除方式称为逻辑删除或软删除。 2.2.为什么使用逻辑删除当我们使用物理删除时,数据将被永久删除,无法恢复。但有些情况下,我们并不希望永久删除数据,比如用户误删除、操作失误等情况,这时逻辑删除就尤为重要。 另外,逻辑删除还可以对应业务层逻辑,将数据状态标志为“已删除”,便于后续查询和统计。同时,逻辑删除还能提高删除操作效率,减少物理删除数据对系统性能的影响。 2.3.综合案例 2.3.1.官方提示说明:只对自动注入的 sql 起效。 插入: 不作限制 查找: 追加 where 条件过滤掉已删除数据,如果使用 wrapper.entity 生成的 where 条件也会自动追加该字段 更新: 追加 where 条件防止更新到已删除数据,如果使用 wrapper.entity 生成的 where 条件也会自动追加该字段 删除: 转变为 更新 例如: 删除: update user set deleted=1 where id = 1 and deleted=0 查找: select id,name,deleted from user where deleted=0 字段类型支持说明: 支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime) 如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now() 附录: 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。 2.3.2.配置方式全局配置: 在application.yml中添加全局逻辑删除配置,如下: mybatis-plus: global-config: db-config: logic-delete-field: deleted # 全局逻辑删除的实体字段名 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)在对应的实体类中添加逻辑删除字段,如下: /** * 逻辑删除 */ @TableLogic private Integer deleted;这里不需要配置@TableLogic注解,必须指定@TableField并设置对应数据库中的字段名。 局部配置: 请在实体类对应的逻辑删除属性上加入@TableLogic注解。其中@TableLogic注解属性介绍如下: 属性名类型说明valueString未逻辑删除的值delvalString已逻辑删除的值在实体类上配置逻辑删除字段,如下: /** * 逻辑删除,1=删除,0=正常 */ @TableLogic(value = "0",delval = "1") @TableField("deleted") private Integer deleted; 2.3.3.案例演示编写一个逻辑删除的方法,使用removeById方法进行测试。
请观察idea控制台输出结果,会发现执行removeById方法后,不再显示delete语句,而是update语句。则表示逻辑删除成功,可查看MySQL数据表中的结果。 然后,执行selectList(null)方法,可发现查询语句的where条件后加入逻辑删除字段deleted=0的判断处理,表示只查询出未逻辑删除的数据。 乐观锁( Optimistic Locking )和悲观锁是数据库中的两种并发控制机制。 乐观锁假定数据一般情况下不会发生冲突,因此在读取数据时不会对其加锁,而是在写入时先比较数据版本号(比如时间戳)是否相同,再进行操作。如果版本号相同,则表示该数据没有被其他进程修改,可以进行写操作;如果版本号不同,则表示该数据已经被其他进程修改,写操作会失败,需要重新读取数据进行操作。 乐观锁是为了解决并发过程中数据更新冲突的问题,乐观锁能提高并发过程中的程序吞吐量。 悲观锁则假定数据会发生冲突,因此在读取数据时就会对其加锁,防止其他进程同时修改此数据,直到当前进程操作完成并解锁后,其他进程才能再次操作该数据。 3.2.乐观锁和悲观锁的区别乐观锁和悲观锁的区别主要有以下几点: 加锁时间不同:乐观锁在读取数据时不会对其加锁,而是在写入时进行比较和加锁操作;悲观锁在读取数据时就会对其加锁。 冲突处理方式不同:乐观锁会在写入时进行比较和冲突检测,如果版本号不一致则操作失败,需要重新读取数据;悲观锁则会阻塞其他进程对该数据的访问,直到当前进程完成操作并解锁。 适用场景不同:乐观锁适用于并发量比较小、数据量比较大、操作更多为读取的场景;悲观锁适用于并发量比较大、数据量比较小、操作更多为写入的场景。 总的来说,乐观锁适用于并发冲突较少的场景,可以提高系统的并发性;悲观锁适用于并发冲突较多的场景,可以保证数据的一致性和安全性。 3.3.综合案例使用数据版本(Version)记录机制实现乐观锁,这是乐观锁最常用的一种实现方式。 如何实现乐观锁? @Version 注解标记乐观锁,通过 version 字段来保证数据的安全性,当修改数据的时候,会以 version 作为条件,当条件成立的时候才会修改成功。 1)取出记录时,获取当前 version 2)更新时,带上这个 version 3)执行更新时,update tableName set version = oldVersion + 1 where version = oldVersion 4)如果 version 不对,就更新失败 第一步:给数据库表添加 version 字段,并设置默认值为1 第二步:实体类增加 version 属性,并添加 @Version 注解 第三步:配置乐观锁插件 如果后期还有mybatis-plus的依赖直接在这里加入即可 @Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //注册乐观锁插件 mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } }第四步:测试 @RequestMapping("/upd") public Object upd(Book book){ Book book1 = bookMapper.selectById(book.getId()); book1.setBookname("我是先执行的"); bookMapper.updateById(book1); Book book2 = bookMapper.selectById(book.getId()); book2.setBookname("我是后执行的"); bookMapper.updateById(book2); return '1'; }如果同时让它们获取到version值再进行修改必有一方修改失败 @RequestMapping("/upd") public Object upd(Book book){ Book book1 = bookMapper.selectById(book.getId()); book1.setBookname("我是先执行的"); bookMapper.updateById(book1); Book book2 = bookMapper.selectById(book.getId()); book2.setBookname("我是后执行的"); bookMapper.updateById(book1); bookMapper.updateById(book2); return '1'; }QueryWrapper是Mybatis-Plus提供的一个条件构造器,用于快速构建SQL查询语句的条件部分。通过使用QueryWrapper,我们可以方便地进行单表数据的查询、修改、删除等操作。 QueryWrapper的语法类似于Mybatis的XML文件中的where标签,其最终会被转换为SQL语句的条件部分。我们可以通过链式调用的方式,不断添加查询条件,从而构建出复杂的查询条件。 配置分页插件 @Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //注册乐观锁插件 mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); //注册分页插件 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return mybatisPlusInterceptor; } }实现分页 @RequestMapping("/listpage") public Object listpage(String bookname) { //条件构造器 QueryWrapper wrapper = new QueryWrapper(); //设置条件 wrapper.like("bookname",bookname); //设置分页 Page page = new Page(1,5); Page result = bookService.page(page,wrapper); System.out.println("总记录数:" + result.getTotal()); return result.getResult(); }
到这里我的分享就结束了,欢迎到评论区探讨交流!! 💖如果觉得有用的话还请点个赞吧 💖
|
CopyRight 2018-2019 实验室设备网 版权所有 |