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

posted @ 2020-09-16 11:12  小窝蜗  阅读(326)  评论(0编辑  收藏  举报