Mybatis学习七 (分页)
1.分页的概念
例如,在数据库的某个表里有1000条数据,
我们每次只显示100条数据,在第1页显示第0到第99条,
在第2页显示第100到199条,依次类推,这就是分页。
分页可以分为逻辑分页和物理分页。
逻辑分页是我们的程序在显示每页的数据时,
首先查询得到表中的1000条数据,然后成熟根据当前页的“页码”选出其中的100条数据来显示。
物理分页是程序先判断出该选出这1000条的第几条到第几条,
然后数据库根据程序给出的信息查询出程序需要的100条返回给我们的程序。
2.MyBatis 物理分页
实现逻辑分页:
MyBatis使用RowBounds实现的分页是逻辑分页,
也就是先把数据记录全部查询出来,然在再根据 offset 和 limit 截断记录返回。
物理分页
为了在数据库层面上实现物理分页,又不改变原来 MyBatis 的函数逻辑,
可以编写 plugin 截获 MyBatis Executor 的 statementhandler,重写SQL来执行查询。
3.开发步骤
第一步:示例功能描述
使用 MyBatis和Spring MVC整合完成分页,完成这样的一个简单功能,即指定一个用户(ID=1),
查询出这个用户关联的所有订单分页显示出来(使用的数据库是:MySQL)
第二步:创建工程
Configuration.xml
applicationContext.xml
第三步:数据库表结构及数据记录
第四步:实例对象
第五步:配置文件
applicationContext.xml
Configuration.xml
UserMaper.xml
第六步:测试执行,输出结果
工具类:PagePlugin.java,Page.java, PageHelper.java,其中 PagePlugin 是针对 MyBatis 分页的插件。
PagePlugin:
@Intercepts( { @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) }) public class PagePlugin implements Interceptor { private static String dialect = ""; private static String pageSqlId = ""; @SuppressWarnings("unchecked") public Object intercept(Invocation ivk) throws Throwable { if (ivk.getTarget() instanceof RoutingStatementHandler) { RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk .getTarget(); BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper .getValueByFieldName(statementHandler, "delegate"); MappedStatement mappedStatement = (MappedStatement) ReflectHelper .getValueByFieldName(delegate, "mappedStatement"); if (mappedStatement.getId().matches(pageSqlId)) { BoundSql boundSql = delegate.getBoundSql(); Object parameterObject = boundSql.getParameterObject(); if (parameterObject == null) { throw new NullYiibaierException("parameterObject error"); } else { Connection connection = (Connection) ivk.getArgs()[0]; String sql = boundSql.getSql(); String countSql = "select count(0) from (" + sql + ") myCount"; System.out.println("总数sql 语句:" + countSql); PreparedStatement countStmt = connection .prepareStatement(countSql); BoundSql countBS = new BoundSql(mappedStatement .getConfiguration(), countSql, boundSql .getParameterMappings(), parameterObject); setParameters(countStmt, mappedStatement, countBS, parameterObject); ResultSet rs = countStmt.executeQuery(); int count = 0; if (rs.next()) { count = rs.getInt(1); } rs.close(); countStmt.close(); Page page = null; if (parameterObject instanceof Page) { page = (Page) parameterObject; page.setTotalResult(count); } else if (parameterObject instanceof Map) { Map<String, Object> map = (Map<String, Object>) parameterObject; page = (Page) map.get("page"); if (page == null) page = new Page(); page.setTotalResult(count); } else { Field pageField = ReflectHelper.getFieldByFieldName( parameterObject, "page"); if (pageField != null) { page = (Page) ReflectHelper.getValueByFieldName( parameterObject, "page"); if (page == null) page = new Page(); page.setTotalResult(count); ReflectHelper.setValueByFieldName(parameterObject, "page", page); } else { throw new NoSuchFieldException(parameterObject .getClass().getName()); } } String pageSql = generatePageSql(sql, page); System.out.println("page sql:" + pageSql); ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); } } } return ivk.proceed(); } private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql, Object parameterObject) throws SQLException { ErrorContext.instance().activity("setting parameters").object( mappedStatement.getParameterMap().getId()); List<ParameterMapping> parameterMappings = boundSql .getParameterMappings(); if (parameterMappings != null) { Configuration configuration = mappedStatement.getConfiguration(); TypeHandlerRegistry typeHandlerRegistry = configuration .getTypeHandlerRegistry(); MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject); for (int i = 0; i < parameterMappings.size(); i++) { ParameterMapping parameterMapping = parameterMappings.get(i); if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); PropertyTokenizer prop = new PropertyTokenizer(propertyName); if (parameterObject == null) { value = null; } else if (typeHandlerRegistry .hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (propertyName .startsWith(ForEachSqlNode.ITEM_PREFIX) && boundSql.hasAdditionalParameter(prop.getName())) { value = boundSql.getAdditionalParameter(prop.getName()); if (value != null) { value = configuration.newMetaObject(value) .getValue( propertyName.substring(prop .getName().length())); } } else { value = metaObject == null ? null : metaObject .getValue(propertyName); } TypeHandler typeHandler = parameterMapping.getTypeHandler(); if (typeHandler == null) { throw new ExecutorException( "There was no TypeHandler found for parameter " + propertyName + " of statement " + mappedStatement.getId()); } typeHandler.setParameter(ps, i + 1, value, parameterMapping .getJdbcType()); } } } } private String generatePageSql(String sql, Page page) { if (page != null && (dialect != null || !dialect.equals(""))) { StringBuffer pageSql = new StringBuffer(); if ("mysql".equals(dialect)) { pageSql.append(sql); pageSql.append(" limit " + page.getCurrentResult() + "," + page.getShowCount()); } else if ("oracle".equals(dialect)) { pageSql .append("select * from (select tmp_tb.*,ROWNUM row_id from ("); pageSql.append(sql); pageSql.append(") tmp_tb where ROWNUM<="); pageSql.append(page.getCurrentResult() + page.getShowCount()); pageSql.append(") where row_id>"); pageSql.append(page.getCurrentResult()); } return pageSql.toString(); } else { return sql; } } public Object plugin(Object arg0) { // TODO Auto-generated method stub return Plugin.wrap(arg0, this); } public void setProperties(Properties p) { dialect = p.getProperty("dialect"); if (dialect == null || dialect.equals("")) { try { throw new PropertyException("dialect property is not found!"); } catch (PropertyException e) { // TODO Auto-generated catch block e.printStackTrace(); } } pageSqlId = p.getProperty("pageSqlId"); if (dialect == null || dialect.equals("")) { try { throw new PropertyException("pageSqlId property is not found!"); } catch (PropertyException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
结果:
学习来源:https://www.yiibai.com/mybatis/mybatis_pagination.html#article-start