看完趣味数学书后,开始技术填坑之路
通常在业务中,需要进行数据分页查询,这样一来,每条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(); } 复制代码