如何做系列(1)- mybatis 如何实现分页?
2016-07-14 19:22
736 查看
第一个做法,就是直接使用我们的sql语句进行分页,也就是在mapper里面加上分页的语句就好了。
然后我们在使用这个dao的时候,传入我们的分页的参数,就可以实现我们的分页需求了。其实很简单。
第二个做法,是一个更为通用的做法,那就是利用mybatis的拦截器,拦截每一个sql,在需要分页的sql加上分页的语句,就可以实现我们的分页功能。
我们可以查看 org.mybatis.spring.SqlSessionFactoryBean,其实他有一个plugin属性,我们可以配置实现一个插件来实现我们的需求。
首先说明一下实现的流程
例如我们有一条sql
String sql =select * from tableXXX where a=xxxx
我们的 拦截器拦截这条sql,然后判断是否是需要分页的,然后将这条sql转化为分页的sql
这样我们就可以得到分页的总页数了。
然后, 拼上我们传入的分页数据,哪一页,每一页几条数据:
select * from ( select row_.*, rownum rownum_ from ( sql ) row_ ) where rownum_ <= endString and rownum_ > offsetPlaceholder
这样我们就可以得到我们本页的返回了。
具体的代码如下:
首先是实现了ibatis intercepter的pageplugin
然后是实现了dialect的oracledialect 数据库方言让我们区分不同的数据库不同的sql语句
配置mybatis.xml
我们需要在sqlSessionFactory中注册我们的插件,发挥效果
至此,我们的分页效果就做出来了。
charles at P.P 2016-7-14
<select id="" parameterType="" resultType="" resultMap=""> Select ROWNUM,ID,NAME FROM(Select ROWNUM as ROWNO, ID,NAME from CHANGED_CONTENT <where> <![CDATA[ROWNUM <= #{endRow}]]> </where> ) <where> <![CDATA[ROWNO > #{startRow}]]> </where> </select>
然后我们在使用这个dao的时候,传入我们的分页的参数,就可以实现我们的分页需求了。其实很简单。
第二个做法,是一个更为通用的做法,那就是利用mybatis的拦截器,拦截每一个sql,在需要分页的sql加上分页的语句,就可以实现我们的分页功能。
我们可以查看 org.mybatis.spring.SqlSessionFactoryBean,其实他有一个plugin属性,我们可以配置实现一个插件来实现我们的需求。
首先说明一下实现的流程
例如我们有一条sql
String sql =select * from tableXXX where a=xxxx
我们的 拦截器拦截这条sql,然后判断是否是需要分页的,然后将这条sql转化为分页的sql
<span style="font-family: 微软雅黑; background-color: rgb(255, 255, 255);"> String countSql = "select count(1) from (" + sql + ") tmp_count" </span>
这样我们就可以得到分页的总页数了。
然后, 拼上我们传入的分页数据,哪一页,每一页几条数据:
select * from ( select row_.*, rownum rownum_ from ( sql ) row_ ) where rownum_ <= endString and rownum_ > offsetPlaceholder
这样我们就可以得到我们本页的返回了。
具体的代码如下:
首先是实现了ibatis intercepter的pageplugin
public class PagePlugin implements Interceptor { private static Logger log = Logger.getLogger("page plugin"); private static Dialect dialectObject = null; // 数据库方言 private static String pageSqlId = ""; // mybaits的数据库xml映射文件中需要拦截的ID(正则匹配) public Object intercept(Invocation ivk) throws Throwable { if (ivk.getTarget() instanceof RoutingStatementHandler) { log.info("com.dragon.dao.pulgin.mybatis.plugin.PagePlugin.intercept() enter*****************"); RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk .getTarget(); BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper .getValueByFieldName(statementHandler, "delegate"); MappedStatement mappedStatement = (MappedStatement) ReflectHelper .getValueByFieldName(delegate, "mappedStatement"); /** * 方法1:通过ID来区分是否需要分页..*query.* 方法2:传入的参数是否有page参数,如果有,则分页, */ if (mappedStatement.getId().matches(pageSqlId)) { // 拦截需要分页的SQL BoundSql boundSql = delegate.getBoundSql(); Object parameterObject = boundSql.getParameterObject();// 分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空 if (parameterObject == null) { //throw new NullPointerException("boundSql.getParameterObject() is null!"); return ivk.proceed(); } else { PageView pageView = null; if (parameterObject instanceof PageView) { // 参数就是Pages实体 pageView = (PageView) parameterObject; } else if (parameterObject instanceof Map) { for (Entry entry : (Set<Entry>) ((Map) parameterObject).entrySet()) { if (entry.getValue() instanceof PageView) { pageView = (PageView) entry.getValue(); break; } } } else { // 参数为某个实体,该实体拥有Pages属性 pageView = ReflectHelper.getValueByFieldType( parameterObject, PageView.class); if (pageView == null) { return ivk.proceed(); } } String sql = boundSql.getSql(); PreparedStatement countStmt = null; ResultSet rs = null; try { Connection connection = (Connection) ivk.getArgs()[0]; String countSql = "select count(1) from (" + sql + ") tmp_count"; // 记录统计 countStmt = connection.prepareStatement(countSql); ReflectHelper.setValueByFieldName(boundSql, "sql", countSql); DefaultParameterHandler parameterHandler = new DefaultParameterHandler( mappedStatement, parameterObject, boundSql); parameterHandler.setParameters(countStmt); rs = countStmt.executeQuery(); Long count = 0L; if (rs.next()) { count = ((Number) rs.getObject(1)).longValue(); } pageView.setRowCount(count); } finally { try { rs.close(); } catch (Exception e) { } try { countStmt.close(); } catch (Exception e) { } } String pageSql = generatePagesSql(sql, pageView); ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql. } } } return ivk.proceed(); } /** * 根据数据库方言,生成特定的分页sql * * @param sql * @param page * @return */ private String generatePagesSql(String sql, PageView page) { if (page != null && dialectObject != null) { //pageNow默认是从1,而已数据库是从0开始计算的.所以(page.getPageNow()-1) int pageNow = page.getPageNow(); return dialectObject.getLimitString(sql, (pageNow <= 0 ? 0 : pageNow - 1) * page.getPageSize(), page.getPageSize()); } return sql; } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties p) { String dialect = ""; // 数据库方言 dialect = p.getProperty("dialect"); if (StringUtils.isBlank(dialect)) { try { throw new PropertyException("dialect property is not found!"); } catch (PropertyException e) { log.error(e); } } else { try { dialectObject = (Dialect) Class.forName(dialect) .getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException(dialect + ", init fail!\n" + e); } } pageSqlId = p.getProperty("pageSqlId");//根据id来区分是否需要分页 if (StringUtils.isBlank(pageSqlId)) { try { throw new PropertyException("pageSqlId property is not found!"); } catch (PropertyException e) { log.error(e); } } } }
然后是实现了dialect的oracledialect 数据库方言让我们区分不同的数据库不同的sql语句
public class OracleDialect extends Dialect { public boolean supportsLimit() { return true; } public boolean supportsLimitOffset() { return true; } public String getLimitString(String sql, int offset, String offsetPlaceholder, int limit, String limitPlaceholder) { sql = sql.trim(); boolean isForUpdate = false; if (sql.toLowerCase().endsWith(" for update")) { sql = sql.substring(0, sql.length() - 11); isForUpdate = true; } StringBuffer pagingSelect = new StringBuffer(sql.length() + 100); if (offset > 0) { pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( "); } else { pagingSelect.append("select * from ( "); } pagingSelect.append(sql); if (offset > 0) { // int end = offset+limit; String endString = offsetPlaceholder + "+" + limitPlaceholder; pagingSelect.append(" ) row_ ) where rownum_ <= " + endString + " and rownum_ > " + offsetPlaceholder); } else { pagingSelect.append(" ) where rownum <= " + limitPlaceholder); } if (isForUpdate) { pagingSelect.append(" for update"); } return pagingSelect.toString(); } }
配置mybatis.xml
我们需要在sqlSessionFactory中注册我们的插件,发挥效果
<bean id="pagePlugin" class="com.xxxxx.pulgin.mybatis.plugin.PagePlugin"> <property name="properties"> <props> <prop key="dialect">com.dragon.dao.pulgin.jdbc.dialet.OracleDialect</prop> <prop key="pageSqlId">.*query.*</prop> </props> </property> </bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:spring/mybatis.xml" /> <property name="plugins"> <array> <ref bean="pagePlugin" /> </array> </property> <property name="mapperLocations"> <list> <!-- 自动匹配Mapper映射文件 --> <value>classpath:com/xxxxx/mapper/*-mapper.xml</value> </list> </property> </bean>
至此,我们的分页效果就做出来了。
charles at P.P 2016-7-14
相关文章推荐
- Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
- nginx介绍
- 《算法导论》第二天
- 借助 windows cmd 批量创建文件夹
- Letter Combinations of a Phone Number
- hdu 5640(切蛋糕)
- Android Studio 对GitHub开源项目的引用及导入
- 集合的常用知识
- Flex上传文件Java端解决中文乱码问题
- 调试JS的技巧
- HTTP头域列表与解释 之 request篇
- svn merge 回滚
- hdu 5146 Sequence(序列操作)
- 安装Express
- Windows下Nginx日志分割
- 前端学习知识库
- sql数据库杂七杂八
- 自动订餐系统
- CocoaPods安装使用
- 可重入函数与线程安全的区别与联系