首页  |  知识库  |  资源下载  |  在线工具  |  A-Z  •  JAR  •  名词查         

关于PostgreSql实现分页查询PostgreSqlPaginatedEnhance常用方法操作代码示例

标签:PostgreSql,分页查询,PostgreSqlPaginatedEnhance,postgresql     发布时间:2018-09-29   

一、前言

基于PostgreSQL数据库,通过定义PostgreSqlPaginatedEnhance实现类及AbstractPaginatedEnhance抽象类实现常用分页查询调用方法,详情参见代码示例。

二、代码示例

1. PostgreSqlPaginatedEnhance类

import java.util.ArrayList;@b@import java.util.List;@b@import java.util.Map; @b@import net.sf.cglib.proxy.Enhancer; @b@import org.springframework.stereotype.Component; @b@import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;@b@@b@@Component("postgreSqlPaginatedEnhance")@b@@SuppressWarnings({ "rawtypes", "unchecked" })@b@public class PostgreSqlPaginatedEnhance extends AbstractPaginatedEnhance {@b@@b@  public String getCountSql(String sql) {@b@    return "select count(*) from (" + sql + ") as st";@b@  }@b@@b@ @b@  public Map pagedMap(Map map, int skip, int pageSize) {@b@    int start = skip;@b@    int end = pageSize;@b@    map.put(START_PROP, Integer.valueOf(start));@b@    map.put(END_PROP, Integer.valueOf(end));@b@    return map;@b@  }@b@@b@  public Object pagedObject(Object value, int skip, int pageSize) {@b@    // rownum 从1开始@b@    int start = skip;@b@    int end = pageSize;@b@@b@    // java bean@b@    Enhancer enhancer = new Enhancer();@b@    enhancer.setCallback(new PagedHandler(value, end, start)); // 问题@b@    enhancer.setSuperclass(value.getClass());@b@    enhancer.setInterfaces(ADD_ON);@b@    return enhancer.create();@b@  }@b@@b@  public String getQuerySql(String sql) { @b@    String s = new StringBuffer(sql.length() + 10).append(sql).append(" limit ? OFFSET ? ").toString();@b@    return s;@b@}@b@@b@  @Override@b@  protected List sortParameterMap(List mappingList) {@b@@b@    if (mappingList == null || mappingList.size() < 2) return mappingList;@b@@b@    ParameterMapping t = (ParameterMapping) mappingList.get(0);@b@@b@    if (t.getPropertyName().equals(START_PROP)) return mappingList;@b@@b@    // List newMappingList = new ArrayList();@b@@b@    ParameterMapping startPm = null;@b@    ParameterMapping endPm = null;@b@@b@    for (int i = 0, n = mappingList.size(); i < n && i < 2; i++) {@b@      ParameterMapping pm = (ParameterMapping) mappingList.get(n - 1 - i);@b@      if (pm.getPropertyName().equals(START_PROP)) {@b@        startPm = pm;@b@      }@b@@b@      if (pm.getPropertyName().equals(END_PROP)) {@b@        endPm = pm;@b@      }@b@    }@b@@b@    // 重新对参数进行排序@b@    List newMappingList = getResultMapping(mappingList, startPm, endPm);@b@@b@    return newMappingList;@b@  }@b@@b@  private List getResultMapping(List mappingList, ParameterMapping startPm, ParameterMapping endPm) {@b@    List newMappingList = new ArrayList();@b@    if (startPm != null && endPm != null) {@b@      for (int i = 0, n = mappingList.size(); i < n - 2; i++) {@b@        newMappingList.add(mappingList.get(i));@b@      }@b@      newMappingList.add(startPm);@b@      newMappingList.add(endPm);@b@    } else { // 没有分页关键字 star , end@b@      newMappingList = mappingList;@b@    }@b@    return newMappingList;@b@  }@b@}

2. AbstractPaginatedEnhance类

import java.lang.reflect.Method;@b@import java.sql.SQLException;@b@import java.util.ArrayList;@b@import java.util.Arrays;@b@import java.util.HashMap;@b@import java.util.Iterator;@b@import java.util.List;@b@import java.util.Map;@b@@b@import net.sf.cglib.proxy.Enhancer;@b@@b@import com.ibatis.sqlmap.client.SqlMapClient;@b@import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;@b@import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap;@b@import com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMapping;@b@import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;@b@import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;@b@import com.ibatis.sqlmap.engine.mapping.result.AutoResultMap;@b@import com.ibatis.sqlmap.engine.mapping.result.BasicResultMap;@b@import com.ibatis.sqlmap.engine.mapping.result.ResultMap;@b@import com.ibatis.sqlmap.engine.mapping.sql.Sql;@b@import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement;@b@import com.ibatis.sqlmap.engine.mapping.statement.SelectStatement;@b@import com.ibatis.sqlmap.engine.scope.RequestScope;@b@import com.xwood.soofa.service.persistence.dao.ibatis.DelegateSql;@b@import com.xwood.soofa.service.persistence.dao.ibatis.SqlMapClientTemplate;@b@import com.xwood.soofa.service.persistence.dao.ibatis.enhance.IbatisPlugin;@b@import com.xwood.soofa.service.persistence.dao.ibatis.enhance.SqlMapEnhance;@b@@b@abstract public class AbstractPaginatedEnhance implements SqlMapEnhance {@b@@b@	protected static final String START_GETTER = "getStartPosition_";@b@@b@	protected static final String START_PROP = "startPosition_";@b@@b@	protected static final String END_GETTER = "getEndPosition_";@b@@b@	protected static final String END_PROP = "endPosition_";@b@@b@	// 使用一个特殊的key传输原始类型@b@	private static final Object INLINE_VALUE_KEY = new Object();@b@@b@	public class CountSql extends DelegateSql {@b@		public CountSql(Sql sql) {@b@			super(sql);@b@		}@b@@b@		@Override@b@		protected String decorateSql(String sql) {@b@			return getCountSql(sql);@b@		}@b@	}@b@@b@	public class QuerySql extends DelegateSql {@b@		public QuerySql(Sql sql) {@b@			super(sql);@b@		}@b@@b@		/**@b@		 * 动态查询参数Mapping需要每次执行的时候构建,同时调整输入参数@b@		 */@b@		@Override@b@		public ParameterMap getParameterMap(RequestScope request,@b@				Object parameter) {@b@@b@			// 根据实际参数情况来处理是否需要调整@b@			BasicParameterMap map = (BasicParameterMap) super.getParameterMap(@b@					request, parameter);@b@			ParameterMapping[] mappings = map.getParameterMappings();@b@			if (needRemapping(mappings)) {@b@				List mappingList = getParameterMappingList(mappings,@b@						map.getDelegate(), request.getStatement());@b@@b@				map.setParameterMappingList(mappingList);@b@				mappings = map.getParameterMappings();@b@				mappingList = null;@b@			}@b@@b@			if (null != parameter) {@b@				if (parameter instanceof Map) {@b@					swapOutInlineValue(mappings[0].getPropertyName(),@b@							(Map) parameter);@b@				}@b@			}@b@@b@			/**@b@			 * 根据不同数据库重新排列参数顺序@b@			 */@b@			List mappingList1 = new ArrayList();@b@			mappingList1.addAll(Arrays.asList(mappings));@b@@b@			mappingList1 = sortParameterMap(mappingList1);@b@@b@			map.setParameterMappingList(mappingList1);@b@@b@			mappingList1 = null;@b@@b@			return map;@b@		}@b@@b@		private boolean needRemapping(ParameterMapping[] mappings) {@b@			if (mappings.length < 2) {@b@				return true;@b@			}@b@			if (!((START_PROP).equals(mappings[mappings.length - 1]@b@					.getPropertyName()))) {@b@				return true;@b@			}@b@@b@			return false;@b@@b@		}@b@@b@		@Override@b@		protected String decorateSql(String sql) {@b@			String s = getQuerySql(sql);@b@@b@			return s;@b@		}@b@	}@b@@b@	/**@b@	 * count sql语句,简单采用nest query方式@b@	 * @b@	 * @param sql@b@	 * @return@b@	 */@b@	abstract protected String getCountSql(String sql);@b@@b@	 @b@	abstract protected String getQuerySql(String sql);@b@@b@	/**@b@	 * <p>@b@	 * ?根据数据库类型进行参数排序@b@	 * </p>@b@	 * @b@	 * @param@b@	 * @return@b@	 * @throws@b@	 * @see@b@	 * @since %I%@b@	 */@b@	abstract protected List sortParameterMap(List mappingList);@b@@b@	@b@	@b@	/**@b@	 * 对需要分页的查询,重新创建两个statement: !count和!paged@b@	 */@b@	@Override@b@	public void enhance(SqlMapClient sqlMapClient) throws Exception {@b@		SqlMapExecutorDelegate delegate = IbatisPlugin@b@				.getDelegate(sqlMapClient);@b@		for (Iterator it = queryStatements.iterator(); it.hasNext();) {@b@			String id = (String) it.next();@b@			MappedStatement statement = IbatisPlugin.getStatement(delegate@b@					.getMappedStatement(id));@b@			if (statement instanceof SelectStatement) {@b@				SelectStatement select = (SelectStatement) statement;@b@				String countId = getCountId(id);@b@				// 避免重复追加,同时,也提供了通过配置来覆盖默认实现的可能@b@				if (!IbatisPlugin.hasStatement(delegate, countId)) {@b@					// 创建count Statement@b@					SelectStatement count = new SelectStatement();@b@					count.setFetchSize(new Integer(1));@b@					count.setId(countId);@b@					count.setSql(new CountSql(select.getSql()));@b@					count.setParameterMap(select.getParameterMap());@b@					count.setParameterClass(select.getParameterClass());@b@					count.setSqlMapClient(select.getSqlMapClient());@b@					count.setResource("PafaHugePagedQuery!count:"@b@							+ select.getResource());@b@					count.setResultMap(buildCountResultMap(delegate, count));@b@					count.setBaseCacheKey(delegate.hashCode());@b@					addMappedStatement(delegate, count);@b@				}@b@				String queryId = getQueryId(id);@b@				if (!IbatisPlugin.hasStatement(delegate, queryId)) {@b@					// 翻页查询Statement@b@					SelectStatement pagedQuery = new SelectStatement();@b@					// pagedQuery.setFetchSize(new Integer(1)); // prefer@b@					// pageSize@b@					pagedQuery.setSqlMapClient(select.getSqlMapClient());@b@					// 沿用原有ResultMap即可@b@					pagedQuery@b@							.setResultMap(buildPageResultMap(delegate, select));@b@					pagedQuery.setResource("PafaHugePagedQuery!Query:"@b@							+ select.getResource());@b@					pagedQuery.setId(queryId);@b@					pagedQuery.setSql(new QuerySql(select.getSql()));@b@					// 调整参数类型@b@					Class targetType = getQueryParameterClass(delegate, select);@b@					pagedQuery.setParameterClass(targetType);@b@					ParameterMap oldMap = select.getParameterMap();@b@					if (null != oldMap) {@b@						// 调整参数Mapping@b@						BasicParameterMap newMap = new BasicParameterMap(@b@								delegate);@b@						newMap.setId(pagedQuery.getId() + "-autoParameterMap");@b@						newMap.setResource("PafaHugePagedQuery");@b@						newMap.setParameterClass(pagedQuery.getParameterClass());@b@						ParameterMapping[] mappings = oldMap@b@								.getParameterMappings();@b@						if (null == mappings) {@b@							// mappings中,null与 || 0 ==@b@							// mappings.length不同,后者表示没有参数输入@b@							// 动态SQL的ParameterMapping执行的时候才会被创建,参见@see QuerySql@b@							// throw new@b@							// Exception("动态SQL的ParameterMapping执行的时候才会被创建");@b@						} else {@b@							List mappingList = getParameterMappingList(@b@									mappings, delegate, select);@b@							newMap.setParameterMappingList(mappingList);@b@						}@b@						pagedQuery.setParameterMap(newMap);@b@					} else {@b@						// 动态SQL的参数ParameterMap或者ResultMap执行的时候才会被创建@b@						// throw new@b@						// Exception("动态SQL的参数ParameterMap或者ResultMap执行的时候才会被创建");@b@						// System.out.println("##############################" +@b@						// id + " No ParameterMap");@b@					}@b@					addMappedStatement(delegate, pagedQuery);@b@				}@b@			} else {@b@				// error@b@				throw new Exception("只能改进SelectStatement,ID=" + id + "类型是"@b@						+ statement.getStatementType());@b@			}@b@		}@b@	}@b@@b@	private static final Object lock = new Object();@b@@b@	private void addMappedStatement(SqlMapExecutorDelegate delegate,@b@			SelectStatement pagedQuery) {@b@		synchronized (lock) {@b@			delegate.addMappedStatement(pagedQuery);@b@		}@b@	}@b@@b@	/**@b@	 * 构建count后的返回类型,为了有更好的兼容,返回Long@b@	 * @b@	 * @param executorDelegate@b@	 * @param statement@b@	 * @return@b@	 */@b@	private BasicResultMap buildCountResultMap(@b@			SqlMapExecutorDelegate executorDelegate, MappedStatement statement) {@b@		BasicResultMap resultMap;@b@		resultMap = new AutoResultMap(executorDelegate, false);@b@		resultMap.setId(statement.getId() + "-AutoResultMap");@b@		resultMap.setResultClass(Long.class);@b@		// resultMap.setXmlName(xmlResultName);@b@		// resultMap.setResource(statement.getResource());@b@		return resultMap;@b@	}@b@@b@	/**@b@	 * <p>@b@	 * ?为分页单独构造一个resultmap对象@b@	 * </p>@b@	 * @b@	 * @param executorDelegate@b@	 * @param statement@b@	 * @param select@b@	 * @return@b@	 * @throws@b@	 * @see@b@	 * @since %I%@b@	 */@b@	private ResultMap buildPageResultMap(@b@			SqlMapExecutorDelegate executorDelegate,@b@			SelectStatement selectStatement) {@b@		BasicResultMap resultMap;@b@		ResultMap rm = selectStatement.getResultMap();@b@		if (rm instanceof AutoResultMap) {// 如果参数是Map,需重新构建一个ResultMap@b@			resultMap = new AutoResultMap(executorDelegate, true);@b@		} else {// 如果参数是DTO@b@			resultMap = (BasicResultMap) selectStatement.getResultMap();@b@		}@b@		// resultMap = new AutoResultMap(executorDelegate, true);@b@		resultMap.setId(selectStatement.getId() + "-PageResultMap");@b@		resultMap.setResultClass(selectStatement.getResultMap()@b@				.getResultClass());@b@		return resultMap;@b@	}@b@@b@	/**@b@	 * 需要优化翻页(以及count)的查询ID List@b@	 */@b@	private List queryStatements = new ArrayList();@b@@b@	public List getQueryStatements() {@b@		return queryStatements;@b@	}@b@@b@	public void setQueryStatements(List queryStatements) {@b@		this.queryStatements = queryStatements;@b@	}@b@@b@	public Map pagedPrimitive(Object parameter, int skip, int pageSize) {@b@		HashMap params = new HashMap();@b@		// 使用一个特殊的key传输原始类型,传入@b@		params.put(INLINE_VALUE_KEY, parameter);@b@		return pagedMap(params, skip, pageSize);@b@	}@b@@b@	/**@b@	 * 通过cglib来加强对象,从而能够获取startPosition_/endPosition_两个属性@b@	 * @b@	 * @param value@b@	 * @param skip@b@	 * @param pageSize@b@	 * @return@b@	 */@b@	abstract public Object pagedObject(Object value, int skip, int pageSize);@b@@b@	@b@@b@	abstract public Map pagedMap(Map map, int skip, int pageSize);@b@@b@	@b@@b@	/**@b@	 * 获取加强后的对象类型@b@	 * @b@	 * @param type@b@	 * @return@b@	 */@b@	public static Class pagedClass(Class type) {@b@		Enhancer enhancer = new Enhancer();@b@		enhancer.setCallbackType(PagedHandler.class);@b@		enhancer.setSuperclass(type);@b@		enhancer.setInterfaces(ADD_ON);@b@		// enhancer.setClassLoader(loader);@b@		return enhancer.createClass();@b@	}@b@@b@	/**@b@	 * 由于这个接口方法会被用于类的加强,因此必须为public@b@	 */@b@	public static interface Paged {@b@		public int getStartPosition_();@b@@b@		public int getEndPosition_();@b@	}@b@@b@	public static Class[] ADD_ON = { Paged.class };@b@@b@	public static class PagedHandler implements@b@			net.sf.cglib.proxy.InvocationHandler {@b@		PagedHandler(Object value, int iStart, int iEnd) {@b@			this.oldBean = value;@b@			this.start = new Integer(iStart);@b@			this.end = new Integer(iEnd);@b@		}@b@@b@		@Override@b@		public Object invoke(Object proxy, Method method, Object[] args)@b@				throws Throwable {@b@			String name = method.getName();@b@			if (START_GETTER.equals(name)) {@b@				return start;@b@			}@b@			if (END_GETTER.equals(name)) {@b@				return end;@b@			}@b@			return method.invoke(oldBean, args);@b@		}@b@@b@		// 原始对象@b@		private final Object oldBean;@b@@b@		// 起始位置@b@		private final Integer start, end;@b@	}@b@@b@	/**@b@	 * 提供工具方法,获取改进后的SQLMAP中,指定查询ID的count结果@b@	 * @b@	 * @param sqlMapClient@b@	 * @param id@b@	 *            原始查询的ID@b@	 * @param parameter@b@	 *            查询条件@b@	 * @return 返回记录数(long)@b@	 * @throws SQLException@b@	 *             查询发生异常,或者该statement并没有加强时@b@	 */@b@	public long count(SqlMapClientTemplate sqlMapClientTemplate, String id,@b@			Object parameter) throws SQLException {@b@		Object result = sqlMapClientTemplate.queryForObject(getCountId(id),@b@				parameter);@b@		if (null == result)@b@			return 0L;@b@		return ((Long) result).longValue();@b@	}@b@@b@	/**@b@	 * 采用优化的方式,进行翻页查询@b@	 * @b@	 * @param sqlMapClient@b@	 * @param id@b@	 *            原始查询的ID@b@	 * @param parameter@b@	 *            查询条件@b@	 * @param skip@b@	 *            忽略记录的条数,必须 >= 0@b@	 * @param pageSize@b@	 *            查询的最大条数@b@	 * @return 查询的结果@b@	 * @throws SQLException@b@	 */@b@	public List queryForList(SqlMapClientTemplate sqlMapClientTemplate,@b@			String id, Object parameter, int skip, int pageSize)@b@			throws SQLException {@b@		String queryId = getQueryId(id);@b@		Object newParameter = getQueryParameter(@b@				IbatisPlugin@b@						.getDelegate(sqlMapClientTemplate.getSqlMapClient()),@b@				queryId, parameter, skip, pageSize);@b@		List res = sqlMapClientTemplate.queryForList(queryId, newParameter);@b@		return res;@b@	}@b@@b@	/**@b@	 * count对应statement ID@b@	 * @b@	 * @param id@b@	 * @return@b@	 */@b@	public static String getCountId(String id) {@b@		return "_pafacount~" + id;@b@	}@b@@b@	// -- 开始处理翻页综合查询的 -----------@b@	public static String getQueryId(String id) {@b@		return "_pafapage~" + id;@b@	}@b@@b@	/**@b@	 * 一个内部协议,用于处理原始类型参数的传递:由于动态SQL开始的时候并不知道参数名。@b@	 * 因此使用一个特殊的key传输原始类型,这里按参数名把参数置入Map,同时删除特殊的key@b@	 * @b@	 * @param parameterName@b@	 * @param parameter@b@	 */@b@	public static void swapOutInlineValue(String parameterName, Map parameter) {@b@		// 防止重复处理时覆盖@b@		if (!parameter.containsKey(INLINE_VALUE_KEY))@b@			return;@b@		// 不存在参数,防止错误覆盖@b@		if (END_PROP.equals(parameterName) || START_PROP.equals(parameterName)) {@b@			return;@b@		}@b@		// 先删除@b@		Object value = parameter.remove(INLINE_VALUE_KEY);@b@		parameter.put(parameterName, value);@b@	}@b@@b@	public static List getParameterMappingList(ParameterMapping[] mappings,@b@			SqlMapExecutorDelegate delegate, MappedStatement select) {@b@		List mappingList = new ArrayList();@b@		mappingList.addAll(Arrays.asList(mappings));@b@		// parameter需要添加两个参数@b@		// end在前start在后@b@		boolean exists = false;@b@		for (int i = 0, n = (mappings == null ? 0 : mappings.length); i < n@b@				&& i < 2; i++) {@b@			ParameterMapping m = mappings[n - 1 - i];@b@			if (m.getPropertyName().equals(END_PROP)@b@					|| m.getPropertyName().equals(START_PROP)) {@b@				exists = true;@b@				break;@b@			}@b@@b@		}@b@@b@		if (!exists) {@b@			mappingList.add(getIntParameterMapping(END_PROP, delegate, select));@b@			mappingList@b@					.add(getIntParameterMapping(START_PROP, delegate, select));@b@		}@b@		return mappingList;@b@	}@b@@b@	/**@b@	 * 构建integer类型的ParameerMapping,用于处理输入参数@b@	 * @b@	 * @param name@b@	 * @param delegate@b@	 * @param statement@b@	 * @return@b@	 */@b@	public static ParameterMapping getIntParameterMapping(String name,@b@			SqlMapExecutorDelegate delegate, MappedStatement statement) {@b@		BasicParameterMapping start = new BasicParameterMapping();@b@		start.setJavaType(Integer.class);@b@		start.setPropertyName(name);@b@		start.setTypeHandler(delegate.getTypeHandlerFactory().getTypeHandler(@b@				Integer.class));@b@		return start;@b@	}@b@@b@	/**@b@	 * 获取Statement中的ParameterClass,如果没有设置,尝试获取ParameterMap中的设置,没有则返回空@b@	 * 但是注意:动态sql/默认自动识别都没有类别@b@	 * @b@	 * @param statement@b@	 * @return@b@	 */@b@	protected static Class getParameterType(MappedStatement statement) {@b@		Class oldType = statement.getParameterClass();@b@		if (null == oldType) {@b@			if (null != statement.getParameterMap()) {@b@				oldType = statement.getParameterMap().getParameterClass();@b@			}@b@		}@b@		return oldType;@b@	}@b@@b@	/**@b@	 * 根据原有statement中的parameterClass的设置,设置新的查询的ParameterClass。包括很多场景@b@	 * <ul>@b@	 * <li><b>没有设置</b>:parameterClass或者parameterMap中都没有设置parameterClass,也不做设置,@b@	 * 执行时解析实际用户传递的参数</li