1. 程式人生 > 實用技巧 >Mybatis學習七 (分頁)

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