看完趣味数学书后,开始技术填坑之路
通常在业务中,需要进行数据分页查询,这样一来,每条SQL语句都加上limit限制,会多了很多重复的代码,而且每次需要自己在代码中进行偏移量的计算,略微有些麻烦。
还好有大神在 Github 里贡献了分页插件,而且使用起来很方便,了解了一下使用原理,发现是使用了MyBatis里面的拦截器Interceptor,学习记录一下。
一般JavaWeb项目使用到的是maven和gradle进行项目管理
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>最新版本</version>
</dependency>
···
// https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper
compile group: 'com.github.pagehelper', name: 'pagehelper', version: '5.1.4'
复制代码
在mybatis-config或者spring中进行配置
mybatis:
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
<property name="param1" value="value1"/>
</plugin>
</plugins>
spring:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:mapping/*.xml">
</property>
<!-- 配置分页插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<value>
reasonable=true
</value>
</property>
</bean>
</array>
</property>
</bean>
复制代码
为了简单,使用了单表查询
<select id="selectByUserId" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM course_user
WHERE user_id = #{userId, jdbcType=INTEGER}
</select>
复制代码
// 使用这个方法,接下来的第一个select方法会进行分页 PageHelper.startPage(1, 5); List<CourseUser> list = mapper.selectByUserId(userId); // 查询结果list类型是Page<E>,要取出分页信息,可以强转,也可以使用PageInfo // 用PageInfo对结果进行包装 PageInfo page = new PageInfo(list); // 获取总数量 int count = page.getTotal(); 复制代码
该插件支持很多数据库,Oracle、MySQL、mongdb等都支持,一般常用的话是MySQL,测试用的项目也是使用MySQL作为持久层,该分页插件可以通过autoDialect自动方言适配了MySQL。
插件通过MyBatis的 拦截器Interceptor进行SQL重写 ,可以从源码中看出
/**
* 获取智能的countSql
*
* @param sql
* @param name 列名,默认 0
* @return
*/
public String getSmartCountSql(String sql, String name) {
//解析SQL
Statement stmt = null;
//特殊sql不需要去掉order by时,使用注释前缀
if(sql.indexOf(KEEP_ORDERBY) >= 0){
return getSimpleCountSql(sql);
}
try {
stmt = CCJSqlParserUtil.parse(sql);
} catch (Throwable e) {
//无法解析的用一般方法返回count语句
return getSimpleCountSql(sql);
}
Select select = (Select) stmt;
SelectBody selectBody = select.getSelectBody();
try {
//处理body-去order by
processSelectBody(selectBody);
} catch (Exception e) {
//当 sql 包含 group by 时,不去除 order by
return getSimpleCountSql(sql);
}
//处理with-去order by
processWithItemsList(select.getWithItemsList());
//处理为count查询
sqlToCount(select, name);
String result = select.toString();
return result;
}
复制代码
@Override
public String getPageSql(String sql, Page page, CacheKey pageKey) {
StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);
sqlBuilder.append(sql);
// 判断是不是第一页,如果是第一页,不需要设置偏移量
if (page.getStartRow() == 0) {
sqlBuilder.append(" LIMIT ? ");
} else {
sqlBuilder.append(" LIMIT ?, ? ");
}
pageKey.update(page.getPageSize());
return sqlBuilder.toString();
}
复制代码