sql2java-pagehelper:参照Mybatis-PageHelper实现分页查询

sql2java-pagehelper是一款轻量级的SQL到Java代码生成器插件,支持分页查询功能。它通过在ThreadLocal中保存分页查询标志及相关数据,在执行SQL查询时自动添加分页语法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sql2java是我几年年开始写的一个sql2java是一个轻量级数据库(SQL)访问代码(java)生成器。这几年一直在根据工作需要维护升级,最近的项目中需要对数据库的记录提供分页查询功能,于是我参照Mybatis-PageHelper并借用其外部数据格式为sql2java实现的分页功能,将其封装为一个sql2java子项目sqlj2ava-pagehelper。使用方式与Mybatis-Pagehelper基本一致。

基本原理

PageHelper的基本原理是应用层通过调用PageHelper.startPage方法在一个静态全局的线程局部变量(ThreadLocal)中保存分页查询的标志及相关的数据(参见gu.sql2java.pagehelper.Page,参见gu.sql2java.pagehelper.PageHelpergetLocalPage,setLocalPage方法),这样就激活了分页查询功能,

sql2java底层在执行SELECT查询语句时会根据保存在ThreadLocal中的Page对象为应用层提供的SELECT语句自动拼接分页查询语法。如果当前线程的ThreadLocal变量中没有Page对象或Page.enable字段为false那么就是普通的SQL查询。

引入依赖

maven下引入sql2java-pagehelper项目依赖

		<dependency>
			<groupId>com.gitee.com</groupId>
			<artifactId>sql2java-pagehelper</artifactId>
			<version>3.11.1</version>
		</dependency>

调用示例

调用示例如下:

import java.util.List;

import org.junit.BeforeClass;
import org.junit.Test;

import gu.sql2java.Managers;
import gu.sql2java.Managers.Module;
import gu.sql2java.pagehelper.Page;
import gu.sql2java.pagehelper.PageHelper;
import gu.sql2java.pagehelper.PageInfo;
import net.facelib.eam.devicecenter.db.DeviceBean;
import static net.facelib.eam.devicecenter.DaoManagement.DM;
import static net.gdface.utils.SimpleLog.log;

public class PageHelperTest {

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
        // 输出调试信息
		Managers.setDebug(true, Module.BASETABLEMANAGER);
	}
	@SuppressWarnings({ "rawtypes", "resource" })
	@Test
	public void test1LoadByWhere() {
		try {
			// 启动分页查询
			PageHelper.startPage(1, 2);
			 // 正常执行sql2java的SQL查询
			List<DeviceBean> devices = DM.daoLoadDeviceByWhere("WHERE id>0 order by id", 1, -1);
			PageInfo<DeviceBean> pageInfo = PageInfo.of(devices);
			log("pageInfo {}",pageInfo);			
		} finally {
			// 删除ThreadLocal变量
			PageHelper.clearPage();
		} 
	}
}

暂时禁用PageHelper

根据《基本原理》一节中的说明我们知道,PageHelper是依赖线程局部变量(ThreadLocal)来标记是否启动分页查询的。ThreadLocal变量作用于当前线程。当分页查询启动时,在当前线程中调用sql2java的任何SELECT查询都会被视为分页查询。

而在现实的场景中,我们实现一个提供分页查询的服务方法时,有可能往往不会只执行一次SELECT查询就能返回需要的需要数据,有可能在执行主要的分页查询获取数据后还要执行其他的正常查询,在多次查询的结果基础组装用户需要的数据。所以这里就存在分页查询激活的状态下,分页查询和普通查询混合调用。

如果在调用时不加以区分,sql2java会将所有我们希望执行的普通查询都以分页查询对待,那么返回的结果肯定是不对的。

为了能在分页查询激活的状态下,实现执行普通查询。从3.11.1版本起,gu.sql2java.SqlRunner接口(TableManager继承了此接口)增加了runWithNoPage(Callable),runWithNoPage(Runnable)方法,为应用层提供了在分页查询激活的状态下,临时禁用分页查询,执行普通查询的简单方式.

示例如下:

/** 暂时禁用分页查询执行 loadUsingTemplateAsList */        
List<B> beans = deviceManager.runWithNoPage(()->deviceManager.loadUsingTemplateAsList(bean));

@Sql2javaEnablePage注解

gu.sql2java.pagehelper.annotations.Sql2javaEnablePage 是用于服务方法上启动分页查询的注解类。

注解类字段说明如下

字段名默认值默认字段定义值说明
valuetruetrue启用分页查询
pageNumKey"pageNum"1HTTP请求中定义pageNum(页码参数,1-based)的属性名
pageSizeKey"pageSize"10HTTP请求中定义pageSize(每页数量)的属性名
countKey"count"HTTP请求中定义count(是否进行count查询,默认true)的属性名
countColumnKey“countColumn”“0”HTTP请求中定义count查询的字段名的属性名,如果不定义则默认字段名为"0"
### JavaPageHelper 分页查询不起作用的原因及解决方案 #### 一、PageHelper 的工作原理 PageHelper 是一款用于 MyBatis 的分页插件,主要通过拦截 SQL 执行,在执行前修改 SQL 添加 `LIMIT` 或其他数据库特定的分页语句来实现分页功能[^1]。 #### 二、常见原因分析 1. **配置问题** 如果 PageHelper 插件未正确引入或版本不匹配,则可能导致分页失效。确保项目中已加入如下依赖并确认其版本兼容性: ```xml <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>x.x.x</version> </dependency> ``` 2. **Mapper 文件中的命名空间错误** Mapper XML 文件内的 namespace 属性应与接口全限定名一致;否则即使启用了 PageHelper,也无法正常识别对应的 SQL 映射文件[^3]。 3. **SQL 语法结构复杂度超出支持范围** 对于某些复杂的嵌套查询或者联合操作(JOIN),PageHelper 可能无法自动解析这些情况下的分页逻辑,从而抛出异常提示“不支持该 SQL 转换为分页查询!”[^2]。 4. **事务管理影响** 在 Spring Boot 应用程序里,默认情况下每个请求都是独立事务。如果在同一个线程中有多个连续的操作涉及不同表的数据读取/更新,并且其中包含了分页查询的话,可能会由于隔离级别设置不当而造成缓存脏读等问题,进而干扰到实际返回的结果集大小判断。 5. **一对多关联查询引起的 total 错误** 当存在父子关系的对象之间做级联加载时,PageHelper 默认只会对最外层的一条 SELECT 进行截断处理,这就会使得统计总数时不准确。此时可以考虑采用子查询的方式重构原有 SQL 来规避此缺陷[^4]。 #### 三、具体解决措施 - 验证 pom.xml 是否缺少必要的 Maven 构建工具包以及 PageHelper 组件; - 检查 mapper 接口定义是否严格遵循官方文档指导原则; - 尝试简化原始 SQL 表达式的难度等级以便更好地被框架理解; - 修改 application.properties/yml 下关于 transaction manager 和 isolation level 参数项; - 若遇到一对多场景下 count(*) 出现偏差现象,建议参照上述提到的方法调整映射策略或将原本单次大查询拆分成若干个小批次分别获取再汇总计算最终数量。 ```java // 正确使用 PageHelper.startPage 方法的位置应该是在调用 service 查询之前 PageHelper.startPage(pageNum, pageSize); List<User> list = userMapper.selectAll(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值