MyBatisPlus 分页插件和数据库行锁的几点思考

MyBatisPlus 分页插件和数据库行锁的几点思考,第1张

前段时间跟踪 MyBatis 源码,分析 MyBatis 的分页查询结果后,发现传入的IPage 参数结果已经包含了查询数据了,以为分页查询语句的关键在于第一个入参必须是 IPage ,而不需要返回值了呢。

昨天发现不是这么回事儿,本文再回顾一下 MyBatis 分页插件的用法及三个发现:

本文讲解答上面三个问题。

第一步 ,设置分页查询插件。

第二步 ,编写分页查询 DAO 方法:

该方法执行完成后,查询数据会存储到iPage 参数中,可以直接获取方法返回值。值得注意的是,这个方法必须有返回值。

我最初以为,查询结果都存储到参数中了,是不是方法定义中可以不用返回值了。昨天编码时就随手写成这样了:

结果,执行报 了 SQL 异常:

纳闷了半天,这分页查询怎么就变成了单条查询了呢?对比旧项目代码,还原分页查询方法,正常了。

结论 :MyBatisPlus 分页方法返回值必须是IPage ,不能为 void 。

以往页面的分页查询,每页数据都很少,没有发现这个问题。

这次实现的是一个批处理任务,一次处理的数据要尽量大。 iPage 分页参数 size 初始设置为 1000,发现日志输出的记录数总是 500 条 ,分页参数失效了,为何呢?

使用客户端连接数据库查询,一次能取 1000 条,而 MyBatisPlus 分页查询,这个 500 条是谁控制的呢?能否修改呢?

答案是 : PaginationInterceptor 限制了单页条数 500,如果需要,可以这样修改:

业务要求某个任务设计成多机、并行任务,且要保证数据一致。Quartz 框架的分布式任务只能保证任务被一个节点执行,不符合需求,Spring Task 倒是可以实现。

所以问题就变成分布式锁的设计了,参考 Quartz 的集群方案中的锁机制,实现基于数据库行锁的锁。

没测试基于行锁的分布式锁之前,我以为某个事务执行select for update 之后,其他事务再对相同记录执行该 *** 作的话,应该会报异常,导致锁获取失败。

测试发现,某条记录被锁定之后,交互流程大概是这样的:

结论 :数据库记录的行锁是排他的,其他事务会阻塞等待。

辛丑年腊月二十八,上述就是今年最后一个工作日的总结。

收拾收拾,准备迎接农历新年!

mybatis分页插件的配置可以在mybaits的配置文件进行配置,也可以在spring的配置文件中进行配置,两者配置其一即可

上面是 PageHelper 官方给的配置和注释,虽然写的很多,不过确实描述的很明白。

dialect :标识是哪一种数据库,设计上必须。offsetAsPageNum :将 RowBounds 第一个参数 offset 当成 pageNum 页码使用rowBoundsWithCount :设置为 true 时,使用 RowBounds 分页会进行 count 查询reasonable : value=true 时, pageNum 小于1会查询第一页,如果 pageNum 大于 pageSize 会查询最后一页

注:上面的配置只针对于pagehelper4.x版本的,如果你用的是pagehelper5.x版本就要这样配置,注意两个spring配置中的类名不同

1. 在 MyBatis 配置 xml 中配置拦截器插件

2. 在 Spring 配置文件中配置拦截器插件

如果4.x的版本用了5.x的版本报错信息如下springboot 在启动项目的时候就会报错,报错信息有很多,主要是因为

总的来说就是缺少了 com.github.pagehelper.PageInterceptor ,这个是新版拦截器,5.x版本才开始使用,所以在4.x版本这样配置是不行的

那么5.x版本的配置在pagehelper4.x上能生效吗?答案是不行 报错信息如下

新版的拦截器PageInterceptor不能和旧版拦截器相互转换,所以还是不行的。

总的来说,pagehelper4.x就该用4.x的配置,pagehelper5.x就用5.x的配置(官方推荐)

使用mybatis的分页插件时报错: net.sf.jsqlparser.statement.select.PlainSelect.getGroupBy()Lnet/sf/jsqlparse

原因:在使用mybatis分页插件时,需要依赖 jsqlparser

PageHelper的 不同版本依赖不同 的jsqlparser版本

pageHelper4.x依赖版本 jsqlparser-1.3.jar

在配置完mybatis后,pagehelper的业务用法,就以分页查询用户列表为例

添加查询所以用户的 mapper 接口

重点来了,然后在 service 中, 先开启分页 再进行查询 ,然后把查询结果集放入 PageInfo 中

PageHelper.startPage(pageNum, pageSize) 这句非常重要,这段代码表示分页的开始,意思是从第 pageNum 页开始,每页显示 pageSize 条记录。

PageInfo 这个类是插件里的类,这个类里面的属性会在输出结果中显示, 使用 PageInfo 这个类,你需要将查询出来的 list 放进去:

PageHelper输出的数据结构

然后在 controller 层调用该方法设置对应的 pageNum 和 pageSize 就可以了,我设置 pageNum 为1,pageSize 为5,看个输出结果吧

PageInfo这个类里面的属性:

pageNum 当前页

pageSize 每页的数量

size 当前页的数量

orderBy 排序

startRow 当前页面第一个元素在数据库中的行号

endRow 当前页面最后一个元素在数据库中的行号

total 总记录数(所有符合条件的数据总数)

pages 总页数 (这个页数也很好算,每页5条,总共有11条,需要3页才可以显示完)

list 结果集

prePage 前一页

nextPage 下一页

isFirstPage 是否为第一页

isLastPage 是否为最后一页

hasPreviousPage 是否有前一页

hasNextPage 是否有下一页

navigatePages 导航页码数

navigatepageNums 所有导航页号

navigateFirstPage 导航第一页

navigateLastPage 导航最后一页

firstPage 第一页

lastPage 最后一页


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/6709204.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-27
下一篇2023-03-27

发表评论

登录后才能评论

评论列表(0条)

    保存