Mybatis-Plus进阶分页与乐观锁插件及通用枚举和多数据源详解


Posted in Java/Android onMarch 21, 2022

分页插件

  MP中自带了分页插件的功能,只需要在配置类中进行简单的配置即可使用分页的相关功能。分页插件常常与前端的分页显示功能相关,为了在前端美观的显示查询到的数据,通常会使用分页插件,将所有的数据分成许多页一页一页的进行显示,不同页的切换使用按钮来完成 MP的插件配置类

@Configuration
public class MybatisPlusConfiguration {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        // 创建一个MybatisPlus的插件拦截器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 创建分页的插件对象并设置数据库类型
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        paginationInnerInterceptor.setOverflow(true);
        // 设置分页的单页最多条数,默认 500 条,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(500L);

        // 将这个分页插件添加到拦截器中并返回
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

自定义方法并调用分页 mapper定义方法

@Mapper
@Repository
public interface UserMapper extends BaseMapper<User> {

    /**
     * 通过年龄查询用户信息并分页返回
     * @param page 传入一个page对象
     * @param age  年龄
     * @return 返回一个page对象
     */
    Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);
}

映射文件编写SQL语句

<mapper namespace="com.xiaochen.mapper.UserMapper">
    <select id="selectPageVo" resultType="com.xiaochen.domain.User">
        select id,name,age,email from user where age > #{age}
    </select>
</mapper>

测试方法调用自定义方法

@Autowired
UserMapper mapper;

@Test
public void testpage() {

    // 创建一个page对象,设置当前页是第1页,每页包含3条记录
    Page<User> page = new Page<>(2, 3);

    // mapper调用selectPage方法之后将结果返回给上面的page对象
    // 第二个参数null的话就是查询所有的记录,如果有查询条件的话就传一个wrapper对象
   mapper.selectPageVo(page, 20);

    // 当前页的数据
    System.out.println(page.getRecords());
    // 当前是第几页
    System.out.println(page.getCurrent());
    // 总页数
    System.out.println(page.getPages());
    // 每页的记录数
    System.out.println(page.getSize());
    // 总记录数
    System.out.println(page.getTotal());
    // 是否有下一页
    System.out.println(page.hasNext());
    // 是否有上一页
    System.out.println(page.hasPrevious());
}

乐观锁插件

  要想使用乐观锁插件,首先要知道什么是乐观锁以及乐观锁出现的原因。现实生活中,一个管理系统往往不仅仅只有一个管理员,以修改商品价格为例,如果有两个管理员小李和小王商品的原价为100,老板先是让小李将商品的价格上调50,一段时间后让小王将商品的价格下调20,由于小李有事耽搁,两个人同时登录管理系统获取到商品的价格对其分别进行修改操作。如果小李最后完成操作的话商品最终为150元,如果小王最后完成操作的话商品最终为80元,这样的话就会造成最终的价格不是老板想要的130。 要想使用代码实现上述案例的话,使用线程来实现的话更加真实(可以模拟两人处理先后的不确定性),但是为了简化操作,设定最后完成操作的是小王,也即是说最后商品的价格为80

@Test
public void happyLockTest() {
    // 小李查询商品的价格
    Product productLi = mapper.selectById(1);
    // 小王查询到商品的价格
    Product productWang = mapper.selectById(1);
    // +50
    productLi.setPrice(productLi.getPrice() + 50);
    mapper.updateById(productLi);
    // -20
    productWang.setPrice(productWang.getPrice() - 20);
    mapper.updateById(productWang);

    // 查询最终的商品价格
    System.out.println("最终价格为:" + mapper.selectById(1).getPrice());
}

// 控制台最终打印 -> 最终价格为:80

  有问题就有解决问题的方法,出现这个问题的原因就是两个管理员同时获取到了商品的信息并对他进行了修改,如果可以使用锁限制同一时间只能有一个管理员对数据进行修改操作的话,就可以避免这个问题了,这就是悲观锁。

  不对啊,不是说要讲乐观锁的嘛怎么讲到了悲观锁了?悲观锁将整张表锁住了,阻止其他人对表进行修改操作,这样的话对效率有很大的折损。于是乐观锁应运而生,乐观锁允许任何人任何时候对表中数据进行修改,只不过数据表中要添加一个字段表示数据的当前版本号,数据每经过一次更新版本号就相应加一,数据每次更新的时候都会带上版本号字段作为更新的条件。这样的话就可以避免之前的问题了,两人同时获取到的版本都是0,小李修改之后就会将版本字段值加一也就是1,这时小王修改的时候就会查不到表中版本号为0的数据而无法修改。

  这样的话就会避免修改冲突,但是还是无法得到想要的结果,于是可以对两人的修改结果进行判断,如果更新操作的返回结果不是0的话就说明更新成功,否则就再次获取数据表中的信息(这次就是为了获得最新的版本号)再次进行更新操作

  使用MP中的乐观锁插件,首先需要在配置类中将乐观锁插件添加到拦截器中,然后再在实体类中的版本号字段上使用@Version标志,然后就是和平常一样的操作数据库即可,执行更新操作的时候会自动将当前查询到的版本号当做条件拼接到SQL语句中

// 将乐观锁插件添加到拦截器中
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

// 实体类标注版本号
@Version
private Integer version;

// 测试方法,测试两个人最后的修改结果
@Test
public void happyLockTest() {
    // 小李查询商品的价格
    Product productLi = mapper.selectById(1);
    // 小王查询到商品的价格
    Product productWang = mapper.selectById(1);
    // +50
    int result = 0;
    do {
        // 更新失败,重新查询并修改
        productLi = mapper.selectById(1);
        productLi.setPrice(productLi.getPrice() + 50);
        result = mapper.updateById(productLi);
    } while (result == 0);
    // -20
    do {
        // 更新失败,重新查询并修改
        productWang = mapper.selectById(1);
        productWang.setPrice(productWang.getPrice() - 20);
        result = mapper.updateById(productWang);
    } while (result == 0);
    // 查询最终的商品价格
    System.out.println("最终价格为:" + mapper.selectById(1).getPrice());
}

// 控制台最终打印 -> 最终价格为:130

通用枚举类

  对于表中拥有固定几个值的一些字段,可以使用枚举类将比较简单的数字或字符存入到数据库表中,然后将这个简单的数字或字符对应着其具体的字符串表示,比如性别0代表女1代表男。这样就会减轻数据库的存储压力,提高用户的使用体验。 使用MP的通用枚举必须先创建一个枚举类,向外提供属性的getter方法和全参构造器,并使用@EnumValue注解将标识的属性值在数据库中存储

@Getter
@AllArgsConstructor
public enum SexEnum {

    FEMALE(0, "女"),
    MALE(1, "男");

    // 将注解标识的属性值存储到数据库中
    @EnumValue
    private Integer sex;
    private String sexName;
}

  然后实体类中修改字段对应属性的类型为枚举类型,然后重写toString方法,方便查询结果显示为数据表中数字或字符对应的具体的字符串表示

// 修改字段对应属性的类型为枚举类型
private SexEnum sex;

// 重写toString方法
@Override
public String toString() {
    return "User{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", sex=" + sex.getSexName() +
            ", age=" + age +
            ", email='" + email + '\'' +
            ", isDeleted=" + isDeleted +
            '}';
}

  最后在配置文件中设置通用枚举的包,也就是相当于让你写的枚举类生效

mybatis-plus:
  # 设置通用枚举的包
  type-enums-package: com.xiaochen.enums

测试

@Test
public void enumTest() {
    
    User user = new User();
    user.setName("张三");
    user.setAge(23);
    user.setSex(SexEnum.FEMALE);
    mapper.insert(user);

    User user1 = mapper.selectById(6);
    System.out.println(user1);
}

测试结果

Mybatis-Plus进阶分页与乐观锁插件及通用枚举和多数据源详解

多数据源

  多数据源就是在一个程序中同时配置多个数据库作为数据源进行操作,适用于多种场景:纯粹多库、 读写分离、 一主多从、 混合模式等。目前我们就来模拟一个纯粹多库的一个场景,配置两个数据库的两张表,通过一个测试用例分别获取两张表的数据,如果获取到说明多库模拟成功

第一步: 导入依赖

<!--mybatis-的场景启动器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

第二步: 配置文件配置多数据源

spring:
# 配置数据源信息
datasource:
dynamic:
# 设置默认的数据源或者数据源组,当设置的数据源都找不到时使用默认数据源,默认值即为master
primary: master
# 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false匹配不到指定数据源时使用默认数据源
strict: false
datasource:
# 主数据源
master:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus
username: root
password: 123456
# 从数据源
slave_1:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456

第三步: 照常使用方法测试在两个数据库查询两张表,唯一不同的就是在service的实现类上使用@DS注解,标注service实现类的所有方法都是对指定数据源进行操作的

Mybatis-Plus进阶分页与乐观锁插件及通用枚举和多数据源详解

测试类及结果

Mybatis-Plus进阶分页与乐观锁插件及通用枚举和多数据源详解

到此这篇关于Mybatis-Plus进阶分页与乐观锁插件及通用枚举和多数据源详解的文章就介绍到这了,更多相关Mybatis-Plus 分页插件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
手把手教你用SpringBoot将文件打包成zip存放或导出
Jun 11 Java/Android
分享一些Java的常用工具
Jun 11 Java/Android
解决SpringBoot跨域的三种方式
Jun 26 Java/Android
Spring Boot两种全局配置和两种注解的操作方法
Jun 29 Java/Android
Java数组与堆栈相关知识总结
Jun 29 Java/Android
logback 实现给变量指定默认值
Aug 30 Java/Android
maven依赖的version声明控制方式
Jan 18 Java/Android
SpringBoot2零基础到精通之异常处理与web原生组件注入
Mar 22 Java/Android
Netty客户端接入流程NioSocketChannel创建解析
Mar 25 Java/Android
零基础学java之带返回值的方法的定义和调用
Apr 10 Java/Android
Android在Sqlite3中的应用及多线程使用数据库的建议
Apr 24 Java/Android
java中如何截取字符串最后一位
Jul 07 Java/Android
Spring this调用当前类方法无法拦截的示例代码
SpringCloud Feign请求头删除修改的操作代码
Mar 20 #Java/Android
JavaWeb实现显示mysql数据库数据
关于Mybatis中SQL节点的深入解析
springboot 自定义配置 解决Boolean属性不生效
Mar 18 #Java/Android
使用Java去实现超市会员管理系统
Mar 18 #Java/Android
详解Spring Security中的HttpBasic登录验证模式
You might like
php park、unpark、ord 函数使用方法(二进制流接口应用实例)
2010/10/19 PHP
PHP autoload与spl_autoload自动加载机制的深入理解
2013/06/05 PHP
PHP程序漏洞产生的原因分析与防范方法说明
2014/03/06 PHP
php通过exif_read_data函数获取图片的exif信息
2015/05/21 PHP
PHP简单生成缩略图相册的方法
2015/07/29 PHP
Smarty模板引擎缓存机制详解
2016/05/23 PHP
PHP大神的十大优良习惯
2016/09/14 PHP
PHP实现Session入库/存入redis的方法
2017/05/04 PHP
判定是否原生方法的JS代码
2013/11/12 Javascript
JavaScript新窗口与子窗口传值详解
2014/02/11 Javascript
jQuery中对未来的元素绑定事件用bind、live or on
2014/04/17 Javascript
分享五个有用的jquery小技巧
2015/10/08 Javascript
js实现简单的验证码
2015/12/25 Javascript
jQuery Ajax 全局调用封装实例代码详解
2016/06/02 Javascript
深入探讨Vue.js组件和组件通信
2016/09/12 Javascript
Angular使用ng-messages与PHP进行表单数据验证
2016/12/28 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
2017/01/20 Javascript
javascript 使用正则test( )第一次是 true,第二次是false
2017/02/22 Javascript
js获取html页面代码中图片地址的实现代码
2018/03/05 Javascript
详解JavaScript中操作符和表达式
2018/09/12 Javascript
jQuery/JS监听input输入框值变化实例
2019/10/17 jQuery
Python中Scrapy爬虫图片处理详解
2017/11/29 Python
python爬虫爬取某站上海租房图片
2018/02/04 Python
python Tkinter的图片刷新实例
2019/06/14 Python
Django缓存系统实现过程解析
2019/08/02 Python
python并发编程多进程之守护进程原理解析
2019/08/20 Python
Python 实现Numpy中找出array中最大值所对应的行和列
2019/11/26 Python
基于tensorflow指定GPU运行及GPU资源分配的几种方式小结
2020/02/03 Python
探秘TensorFlow 和 NumPy 的 Broadcasting 机制
2020/03/13 Python
美国药妆网站:EDCskincare.com(防晒、痤疮、抗衰老等)
2017/04/28 全球购物
美国高级音响品牌:Master&Dynamic
2018/07/05 全球购物
后勤副校长自我鉴定
2013/10/13 职场文书
销售实习自我鉴定
2013/12/07 职场文书
2016年学校“6﹒26国际禁毒日”宣传活动总结
2016/04/05 职场文书
只需要这一行代码就能让python计算速度提高十倍
2021/05/24 Python
剑指Offer之Java算法习题精讲二叉树专项训练
2022/03/21 Java/Android