MyBatis使用(二)分页查询

由于MyBatis没有相关的分页查询,因此抽取出hibernate的分页查询功能,通过过滤器,对本地sql方言进行区分,对sql语句进行拼接和封装

步骤分为:1、先查询出总数

       2、通过拼接的sql再去查询相关信息

/**
	 * 带有分页信息的查询
	 * @param sqlMapId mybatis映射id
	 * @param pageRequest 分页请求参数信息
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Page findForPage(String sqlMapId, PageRequest pageRequest) {

		// 查询总数
		pageRequest.getFilters().put(SelectCountSqlInterceptor.COUNT, null); // 设置是否需要将sql转换成总数查询sql
		Number totalCount = (Number) findForObject(sqlMapId, pageRequest
				.getFilters());
		if (totalCount == null || totalCount.intValue() <= 0) {
			return new Page(pageRequest, 0);
		}
		if(totalCount != null && totalCount.intValue() <= (pageRequest.getPageNumber()-1) * pageRequest.getPageSize()){
			return new Page(pageRequest.getPageNumber(), pageRequest.getPageSize(), totalCount.intValue(), new ArrayList(0));
		}
		pageRequest.getFilters().remove(SelectCountSqlInterceptor.COUNT);

		Map filters = new HashMap();
		filters.putAll(pageRequest.getFilters());
		Page page = new Page(pageRequest, totalCount.intValue());
		List list = findForList(sqlMapId, filters, page.getFirstResult(), page.getPageSize());

		page.setResult(list);

		return page;
	}

  

/**
 * 分页请求信息
 */
public class PageRequest implements Serializable {

	private static final long serialVersionUID = 9092186838918641382L;

	/**
	 * 过滤参数
	 */
	private Map filters;

	/**
	 * 页号码,页码从1开始
	 */
	private int pageNumber;

	/**
	 * 分页大小
	 */
	private int pageSize;
}

  

/**
 * 将查询SQL转成查询总数SQL<br>
 *
 * 配置文件内容:
 *
 * <pre>
 * 	<plugins>
 * 		<plugin interceptor="ewell.nis.common.ibatis.plugin.SelectCountSqlInterceptor"/>
 * 	</plugins>
 * </pre>
 */
@Intercepts( { @Signature(type = Executor.class, method = "query", args = {
		MappedStatement.class, Object.class, RowBounds.class,
		ResultHandler.class }) })
public class SelectCountSqlInterceptor implements Interceptor {

	public static String COUNT = "_count";

	private static int MAPPED_STATEMENT_INDEX = 0;

	private static int PARAMETER_INDEX = 1;

	@Override
	public Object intercept(Invocation invocation) throws Throwable {

		processCountSql(invocation.getArgs());

		return invocation.proceed();
	}

	private void processCountSql(final Object[] queryArgs) {

		if (queryArgs[PARAMETER_INDEX] instanceof Map) {
			Map parameter = (Map) queryArgs[PARAMETER_INDEX];
			if (parameter.containsKey(COUNT)) {
				MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
				BoundSql boundSql = ms.getBoundSql(parameter);
				String sql = ms.getBoundSql(parameter).getSql().trim();
				BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),
						getCountSQL(sql), boundSql.getParameterMappings(),
						boundSql.getParameterObject());
				MappedStatement newMs = copyFromMappedStatement(ms,
						new BoundSqlSqlSource(newBoundSql));
				queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
			}
		}
	}

	// see: MapperBuilderAssistant
	private MappedStatement copyFromMappedStatement(MappedStatement ms,
			SqlSource newSqlSource) {

		Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms
				.getId(), newSqlSource, ms.getSqlCommandType());

		builder.resource(ms.getResource());
		builder.fetchSize(ms.getFetchSize());
		builder.statementType(ms.getStatementType());
		builder.keyGenerator(ms.getKeyGenerator());
		builder.keyProperty(getKeyProperty(ms.getKeyProperties()));

		// setStatementTimeout()
		builder.timeout(ms.getTimeout());

		// setParameterMap()
		builder.parameterMap(ms.getParameterMap());

		// setStatementResultMap()
		List<ResultMap> resultMaps = new ArrayList<ResultMap>();
		String id = "-inline";
		if (ms.getResultMaps() != null) {
			id = ms.getResultMaps().get(0).getId() + "-inline";
		}
		ResultMap resultMap = new ResultMap.Builder(null, id, Long.class,
				new ArrayList()).build();
		resultMaps.add(resultMap);
		builder.resultMaps(resultMaps);
		builder.resultSetType(ms.getResultSetType());

		// setStatementCache()
		builder.cache(ms.getCache());
		builder.flushCacheRequired(ms.isFlushCacheRequired());
		builder.useCache(ms.isUseCache());

		return builder.build();
	}

	private String getKeyProperty(String[] keyProperties) {

		StringBuilder builder = new StringBuilder();
		if (keyProperties != null && keyProperties.length > 0) {
			int length = keyProperties.length;
			for (int i = 0; i < length; i++) {
				builder.append(keyProperties[i]);
				if (i < length -1) {
					builder.append(",");
				}
			}
			return builder.toString();
		}

		return null;
	}

	private String getCountSQL(String sql) {

		String lowerCaseSQL = sql.toLowerCase().replace("\n", " ").replace(
				"\t", " ");
		int index = lowerCaseSQL.indexOf(" order ");

		if (index != -1) {
			sql = sql.substring(0, index);
		}

		if (lowerCaseSQL.indexOf(" group ") != -1) {
			return "SELECT COUNT(*) FROM (SELECT COUNT(*) AS COUNT_" + sql.substring(lowerCaseSQL.indexOf(" from ")) + ") TABLE_";
		}

		return "SELECT COUNT(*) AS COUNT_" + sql.substring(lowerCaseSQL.indexOf(" from "));
	}

	@Override
	public Object plugin(Object target) {

		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {

	}
}

  

/**
 * 为ibatis3提供基于方言(Dialect)的分页查询的插件<br>
 *
 * 将拦截Executor.query()方法实现分页方言的插入<br>
 *
 * 配置文件内容:
 *
 * <pre>
 * 	<plugins>
 * 	<plugin interceptor="ewell.nis.common.ibatis.plugin.OffsetLimitInterceptor">
 * 		<property name="dialectClass" value="ewell.nis.common.ibatis.dialect.MySQLDialect"/>
 * 	</plugin>
 * </plugins>
 * </pre>
 *
 *
 */

@Intercepts( { @Signature(type = Executor.class, method = "query", args = {
		MappedStatement.class, Object.class, RowBounds.class,
		ResultHandler.class }) })
public class OffsetLimitInterceptor implements Interceptor {

	private static int MAPPED_STATEMENT_INDEX = 0;

	private static int PARAMETER_INDEX = 1;

	private static int ROWBOUNDS_INDEX = 2;

	private Dialect dialect;

	@Override
	public Object intercept(Invocation invocation) throws Throwable {

		processIntercept(invocation.getArgs());
		return invocation.proceed();
	}

	void processIntercept(final Object[] queryArgs) {

		// queryArgs = query(MappedStatement ms, Object parameter, RowBounds
		// rowBounds, ResultHandler resultHandler)
		MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
		Object parameter = queryArgs[PARAMETER_INDEX];
		final RowBounds rowBounds = (RowBounds) queryArgs[ROWBOUNDS_INDEX];
		int offset = rowBounds.getOffset();
		int limit = rowBounds.getLimit();

		if (dialect.supportsLimit()
				&& (offset != RowBounds.NO_ROW_OFFSET || limit != RowBounds.NO_ROW_LIMIT)) {
			BoundSql boundSql = ms.getBoundSql(parameter);
			String sql = boundSql.getSql().trim();
			if (dialect.supportsLimitOffset()) {
				sql = dialect.getLimitString(sql, offset, limit);
				offset = RowBounds.NO_ROW_OFFSET;
			}
			else {
				sql = dialect.getLimitString(sql, 0, offset+limit);
			}
			limit = RowBounds.NO_ROW_LIMIT;

			queryArgs[ROWBOUNDS_INDEX] = new RowBounds(offset, limit);
			BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql,
					boundSql.getParameterMappings(), boundSql
							.getParameterObject());
			MappedStatement newMs = copyFromMappedStatement(ms,
					new BoundSqlSqlSource(newBoundSql));
			queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
		}
	}

	// see: MapperBuilderAssistant
	private MappedStatement copyFromMappedStatement(MappedStatement ms,
			SqlSource newSqlSource) {

		Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms
				.getId(), newSqlSource, ms.getSqlCommandType());

		builder.resource(ms.getResource());
		builder.fetchSize(ms.getFetchSize());
		builder.statementType(ms.getStatementType());
		builder.keyGenerator(ms.getKeyGenerator());
		builder.keyProperty(getKeyProperty(ms.getKeyProperties()));

		// setStatementTimeout()
		builder.timeout(ms.getTimeout());

		// setStatementResultMap()
		builder.parameterMap(ms.getParameterMap());

		// setStatementResultMap()
		builder.resultMaps(ms.getResultMaps());
		builder.resultSetType(ms.getResultSetType());

		// setStatementCache()
		builder.cache(ms.getCache());
		builder.flushCacheRequired(ms.isFlushCacheRequired());
		builder.useCache(ms.isUseCache());

		return builder.build();
	}

	public Object plugin(Object target) {

		return Plugin.wrap(target, this);
	}

	public void setProperties(Properties properties) {

		String dialectClass = new PropertiesHelper(properties)
				.getRequiredString("dialectClass");
		try {
			dialect = (Dialect) Class.forName(dialectClass).newInstance();
		} catch (Exception e) {
			throw new RuntimeException(
					"cannot create dialect instance by dialectClass:"
							+ dialectClass, e);
		}
		System.out.println(OffsetLimitInterceptor.class.getSimpleName()
				+ ".dialect=" + dialectClass);
	}

	private String getKeyProperty(String[] keyProperties) {

		StringBuilder builder = new StringBuilder();
		if (keyProperties != null && keyProperties.length > 0) {
			int length = keyProperties.length;
			for (int i = 0; i < length; i++) {
				builder.append(keyProperties[i]);
				if (i < length -1) {
					builder.append(",");
				}
			}
			return builder.toString();
		}

		return null;
	}

	public static class BoundSqlSqlSource implements SqlSource {

		private BoundSql boundSql;

		public BoundSqlSqlSource(BoundSql boundSql) {

			this.boundSql = boundSql;
		}

		public BoundSql getBoundSql(Object parameterObject) {

			return boundSql;
		}
	}
}

  

  

时间: 2024-10-03 13:45:27

MyBatis使用(二)分页查询的相关文章

Mybatis最入门---分页查询(拦截器分页原理及实现)

[一步是咫尺,一步即天涯] 前文,我们演示了物理分页的Sql实现方式,这种方式使得我们每次在编写查询服务时,不断的重复造轮子.这样的代码实现方式就显得十分的笨拙了.本文是Mybatis分页查询的最后一片内容,我们将介绍基于拦截器的,精巧的实现方式.在阅读这篇文章之前,强烈建议各位看官能够先阅读上文.这样就能对下文我们提及的各种对象及他们之间的关系有一个清晰的关系.好了,废话不多讲,开始我们的正文部分吧. 准备工作: a.操作系统 :win7 x64 b.基本软件:MySQL,Mybatis,SQ

Mybatis+SpringMVC实现分页查询(附源码)

Maven+Mybatis+Spring+SpringMVC实现分页查询(附源码) 一.项目搭建 关于项目搭建,小宝鸽以前写过一篇Spirng+SpringMVC+Maven+Mybatis+MySQL项目搭建,这篇文章提供了详细的搭建过程,而且提供了源码下载,接下来的将在这个源码的基础上继续开发.所以建议各位猿友可以把猿友下载一下. 二.分页插件的介绍 博主采用的插件是PageHelper这个插件,使用起来十分方便.该插件支持以下数据库: Oracle Mysql MariaDB SQLite

SpringMVC+MyBatis+EasyUI 实现分页查询

user_list.jsp <%@ page import="com.ssm.entity.User" %> <%@ page pageEncoding="UTF-8" import="java.util.List" %> <html> <head> <%@ include file="meta.jsp" %> <meta charset="UTF-8

mybatis组合模糊+分页查询

//组合模糊查询就是这么简单 <select id="findAllJiemu" parameterType="java.util.Map" resultMap="ImNoticeJiemu"> SELECT A.*,(select f.names from pt_userinfo f where f.ids = ( select r.userinfoids from pt_user r where r.ids = A.createu

spring-boot 集合mybatis 的分页查询

spring-boot 集合mybatis 的github分页查询 一.依赖包 <!-- mysql 数据库驱动. --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- spring-boot mybatis依赖: 请不要使用1.0.0版本,因为还不支持拦截器

Oracle基本语法&amp;&amp;函数&amp;&amp;子查询&amp;&amp;分页查询&amp;&amp;排序&amp;&amp;集合操作&amp;&amp;高级分组函数

一.  数据库 手工---文件管理---数据库 DB:Database 数据库. DBMS:管理数据库的软件.(oracle) 主流关系数据库: 1.      Oracle 2.      DB2 3.      SQL Server 基本没人使 4.      MySQL  基本没人用,免费 Linux 开源,可以发现漏洞补上 Windows服务器会有补丁,数据易泄漏 eclipse 日食 数据表(Table): 表的行(Row):记录 表的列(Column):字段 二.  关系型数据库 一

SSH初体验系列--Hibernate--3--单值与分页查询

前言 查询可以按结果集分2类:单个结果 和 数组 ; 其中,返回数组,在这个 数据库数据量随随便便就能上几十万的互联网时代大背景下,常常需要做分页处理, 所以这里就说一下单值和分页, 算是对上一篇"curd"的一些延伸 一.单值查询 比如,我们需要查询数据库,统计一下app的当前注册人数, 此时我们知道返回结果必定是"单行单列"的一个数值,那么可以用这种单值查询方式; 使用uniqueResult()方法,它返回一个java.lang.Object对象,并且能保证返

Mybatis的插件 PageHelper 分页查询使用方法

参考:https://blog.csdn.net/ckc_666/article/details/79257028 Mybatis的一个插件,PageHelper,非常方便mybatis分页查询,国内牛人的一个开源项目 github:https://github.com/pagehelper/Mybatis-PageHelper 使用文档:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.

myBatis学习笔记(10)——使用拦截器实现分页查询

1. Page package com.sm.model; import java.util.List; public class Page<T> { public static final int DEFAULT_PAGE_SIZE = 20; protected int pageNo = 1; // 当前页, 默觉得第1页 protected int pageSize = DEFAULT_PAGE_SIZE; // 每页记录数 protected long totalRecord = -1