Java里数据库分页查询那事儿,语句怎么写才靠谱详细讲解
- 问答
- 2026-01-11 18:25:32
- 1
说到Java里做数据库分页查询,这几乎是每个做后台系统的程序员都要碰上的事儿,想象一下,你有个网站,要从数据库里拿出所有用户数据,结果一看,好家伙,一百万条记录,你要是直接一把全查出来,不光数据库扛不住,容易卡死,网络传输也够呛,而且前端页面要显示一百万条数据,用户的浏览器非得崩溃不可,分页查询就是为了解决这个问题:我只拿一小部分,比如一页20条,用户看完了点“下一页”,我再给你拿接下来的20条。
这个“拿一小部分”的语句怎么写才靠谱呢?主要有两种主流的方法,咱们一种一种说。
第一种方法,也是最常见、最推荐的方法,就是使用数据库本身提供的分页关键字。
这个方法的好处是,数据库厂商自己做的优化,效率最高,不同的数据库,语法稍微有点不一样,但思路都一样。
-
MySQL 和 PostgreSQL: 它们用的是
LIMIT关键字,语句长这样:SELECT id, name, email FROM users ORDER BY id DESC LIMIT 0, 20;这句话的意思是:从users表里,按照id倒序排列,然后从第0条记录开始(也就是第一条),一共拿20条,当你点下一页的时候,就把语句改成LIMIT 20, 20,意思是从第20条记录开始(也就是第21条),再拿20条,这里的第一个数字是“偏移量”,第二个数字是“每页大小”。 -
Oracle: 它麻烦一点,需要用
ROWNUM,因为ROWNUM是在数据排序前就分配的,所以不能直接用在WHERE里,通常要套一层子查询,语句大概是这样:SELECT * FROM ( SELECT rownum as rn, a.* FROM ( SELECT id, name, email FROM users ORDER BY id DESC ) a WHERE rownum <= 40 ) WHERE rn > 20;这个语句看着复杂,其实干的事儿和MySQL一样:拿出排好序后的第21到40条记录,内层的a子查询是先排序,中间一层是限制上限(比如到40条),最外层是限制下限(从21条开始)。
-
SQL Server: 比较新的版本(2012以后)支持
OFFSET-FETCH子句,这个就非常直观了,和MySQL的思路很像:SELECT id, name, email FROM users ORDER BY id DESC OFFSET 20 ROWS FETCH NEXT 20 ROWS ONLY;这句话一目了然:排序后,跳过20行,然后取接下来的20行。
在Java代码里怎么用呢? 你肯定不会把SQL语句写死对吧,我们一般会用参数占位符,以最常用的MyBatis框架和MySQL为例,Mapper接口里会定义这样一个方法:
List<User> findUsersByPage(@Param("offset") int offset, @Param("pageSize") int pageSize);
对应的XML映射文件里,SQL这么写:
<select id="findUsersByPage" resultType="User"> SELECT id, name, email FROM users ORDER BY id DESC LIMIT #{offset}, #{pageSize} </select>
然后你在Service层计算一下就行了,比如当前是第page页,每页pageSize条,那么offset就等于 (page - 1) * pageSize。
第二种方法,是使用第三方工具库,比如MyBatis-Plus。

如果你在用MyBatis,那MyBatis-Plus这个插件简直是神器,它把分页这种通用操作都给你封装好了,你几乎不用写任何SQL。(来源:MyBatis-Plus官方文档)
你需要配置一个分页插件,在你的Mapper接口那里,让它继承BaseMapper,在代码里分页就变得超级简单:
Page<User> page = new Page<>(1, 20); // 查询第1页,每页20条
IPage<User> userPage = userMapper.selectPage(page, null);
List<User> records = userPage.getRecords(); // 当前页的数据
long total = page.getTotal(); // 总记录数,这个它自动帮你查了
你看,你都不用关心LIMIT怎么写,它全都帮你生成好了,而且还额外帮你执行了一个COUNT(*)查询来获取总记录数,这样你的分页控件就能显示总页数了,这对于快速开发来说,非常方便。
怎么才叫“靠谱”?总结几点:
- 一定要排序! 这是最最重要的一条,你没有用
ORDER BY指定排序,数据库每次返回的顺序可能是随机的,那你翻页的时候数据可能就乱套了,这绝对是重大事故,排序字段最好用有唯一约束的,比如主键,避免因为排序字段值相同导致分页时数据重复或丢失。 - 首选数据库自带分页。 在性能上,这通常是最优解,特别是
LIMIT和OFFSET,数据库引擎会做优化。 - 注意偏移量过大时的性能问题。 比如你用
LIMIT 1000000, 20,数据库需要先扫描并跳过100万条记录,然后才取20条,当偏移量非常大时,速度会变慢,对于这种深度分页,可以考虑用“上一页最大值”的方式优化,比如记录上一页最后一条记录的ID,然后查WHERE id > 上一页最大ID LIMIT 20,但这种方式不适合直接跳到任意页。 - 考虑使用MyBatis-Plus等工具。 在开发效率要求高、业务逻辑不极端复杂的情况下,用这些封装好的工具能节省大量时间,而且不容易出错。
分页查询的核心思想就是“按需索取”,Java程序员的活儿就是根据你用的数据库和框架,选择最合适、最稳当的方式把这条SQL语句拼装和执行好。
本文由帖慧艳于2026-01-11发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/78840.html
