MyBatis中的RowBounds
发布日期:2021-07-01 01:15:40 浏览次数:2 分类:技术文章

本文共 2397 字,大约阅读时间需要 7 分钟。

转载自  

一、如何分页查询

Mybatis如何分页查询?Mysql中可以使用limit语句,但limit并不是标准SQL中的,如果是其它的数据库,则需要使用其它语句。MyBatis提供了RowBounds类,用于实现分页查询。RowBounds中有两个数字,offset和limit。

 

二、MyBatis如何利用RowBounds实现通用分页

在查询数据库时,如果没有limit语句,则ResultSet中会包含所有满足条件的数据,

RowBounds在处理分页时,只是简单的把offset之前的数据都skip掉,超过limit之后的数据不取出,上图中的代码取自MyBatis中的DefaultResultSetHandler类。跳过offset之前的数据是由方法skipRows处理,判断数据是否超过了limit则是由shouldProcessMoreRows方法进行判断。简单点说道,就是先把数据全部查询到ResultSet,然后从ResultSet中取出offset和limit之间的数据,这就实现了分页查询。

从两种场景下说明RowBounds的使用

    SqlSession,使用SqlSession时,selectList有一个重载的方法,带有RowBounds参数,这种情况下,DAO层的实现了,可以对外界隐藏RowBounds类。如下图,Page是自定义的一个接口,用于表示分页信息,不直接使用RowBounds源于自己的一个习惯,不喜欢在Service层中侵入持久层所使用的持久化技术的类或接口。如果在Service中使用了RowBounds,Service与MyBatis就耦合了,当然,如果不要求这一点,直接要Service里写RowBounds对象也是可以的。

    1.映射接口,MyBatis提供了映射接口的形式,这种情况下,可以不写DAO接口的实现即可完成DAO层,这种情况下,DAO接口写成List<User> vip(RowBounds page),这种情况下,mybatis会完成分页查询。

回到Page接口,如果类与接口之间的关系如右类图,DAO中的方法还是vip(Page page),而调用的时候,工厂返回了一个MyBatisPage类的对象给DAO,因为MyBatisPage类继承自RowBounds类,所以此时传给DAO的Page对象也是一个RowBounds类的对象,但这种情况下却不会有分页查询的效果。

MyBatisPage类相当于一个适配器,用于适配Page接口与RowBounds,但为何给DAO一个RowBounds对象时,却没有实现分页效果,原因是MyBatis判断方法的参数中有没有RowBounds参数是在产生接口的代理时,而不是在方法调用的时候。根据DefaultSqlSession类的getMapper方法可以很快找到MapperProxyFactory类,此类的作用就是创建接口的动态代理,所以方法的调用逻辑应该要看代理的InvocationHandler对象,它是MapperProxy类,这里的处理调用比较深,在MapperProxy类中可以发现,每一个DAO接口上的方法都会对应一个MapperMethod类的对象,MapperMethod类中有一个内部类MethodSignature,这是关键的地方,每一个MapperMethod对象都依赖于一个MethodSignature对象,看看此类的构造器:

rowBoundsIndex,这个属性是用于记录MapperMthod对应的方法的参数中,RowBounds是第几个参数,getUniqueParamIndex方法的实现中,如果发现没有Rowbounds参数,则返回null,由此可见,如果DAO的方法签名为vip(Page page),则rowBoundsIndex为null,所以在调用的时候,即使Page接口的实例也是一个RowBounds的实例,也不会有分页效果。

    如果想要解决这个限制,付出的代价有点大。与Spring框架不同的是,Spring中,类与类之间依赖的是接口而不是具体类。而MyBatis从DefaultSqlSesison到MethodProx,全部依赖的是具体类,这些类没有接口,如果要想解决这个限制,需要子类化DefaultSqlSession,Configuration,MapperRegistry,MapperProxyFactory,MapperProxy,MapperMethod和MethodSignature,这些类都没有实现某个可扩展的接口,甚至没有实现接口,全部是依赖具体的类,无法从其中某个点进行扩展。至于MapperProxyFactory,它无法替换成其它工厂类,它仅仅只是隐藏了接口的代理的创建方式。

 

RowBounds没有覆盖equals和hashCode方法

    如果RowBounds在Service中直接new了,则在测试Service时,在mock时使用了when这样的方法,如:when(userDao.vip(rowBounds)).xxx,那么就会发生错误,因为在Service中也会new一个RowBounds,即使Service中new的那个RowBounds和单元测试中的RowBoumds的offset和limit两个数都一样,rowBounds.equals(row)也不会返回true,当然,可以使用when(userDao.vip(anyObject()))。

如何解决这个问题?有两种方式,一种是RowBounds作为参数传入Service,另一种是使用适配器,这个适配器很简单,写个RowBounds的子类,在子类中覆盖hashCode&equals方法,在Service中使用新的类。

 

转载地址:https://maokun.blog.csdn.net/article/details/104596868 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Maven的pom.xml文件详解------Build Settings
下一篇:MyBatis Generator分页插件RowBoundsPlugin坑

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月25日 16时41分13秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

Android的最小权限原则 2019-05-02
Android四大组件 2019-05-02
操作系统(11) 2019-05-02
数据库复习(2) 2019-05-02
数据库复习(3) 2019-05-02
数据库复习(4) 2019-05-02
C# TextBox输入密码显示星号(*) 2019-05-02
C#如何将文件资源添加到resource下 2019-05-02
Android Studio显示can not resolve symbol intent 2019-05-02
Android活动的生命周期 2019-05-02
我是如何拿到蚂蚁金服offer?看完2020年Java研发岗复盘经验总结,是时候让面试官懵逼了 2019-05-02
阿里Java首席架构师都在看的“MyBatis源码解析文档”你看过吗? 2019-05-02
千万程序员的呼声:面试如何拿到大厂Offer?这份阅读量超过11W+的算法刷题宝典请你原地查收 2019-05-02
Java渣渣外包开发3年,4面终揽下美团,含泪拿到22koffer 2019-05-02
揭秘阿里架构师花费3年总结整理出的“Spring家族清单”网友:万字长文干货!真牛逼 2019-05-02
还有人玩不起“微”服务?看完这份阿里技术专家手写“微服务架构笔记”不在难的! 2019-05-02
Java架构速成笔记:五大专题,1345页考点 看完直接收获腾讯、京东、滴滴offer 2019-05-02
阿里P8架构师倾力推荐,2020年末Java技术栈面试合集,让你进军大厂不在难!! 2019-05-02
全面到哭!阿里内部疯传Netty实战文档程序员必须人手一份 2019-05-02
牛人程序员经阿里4面技术+1面HR,终斩获offer !来大厂面试也不过如此 2019-05-02