[Java][MyBatis]物理分页达成
发布时间:2021-11-20 16:38:32 所属栏目:教程 来源:互联网
导读:Mybatis3.0出来已有段时间了,其实自己挺喜欢这样的一个持久化框架的,因为它简单实用,学习成本低。Mybatis3.0在整体结构上和ibatis2.X差不多,改进特性如下: 1.解析xml引进了Xpath,不像ibatis2.x那样业余 2.动态sql用OGNL解析 3.加入注解配置sql,感觉没
Mybatis3.0出来已有段时间了,其实自己挺喜欢这样的一个持久化框架的,因为它简单实用,学习成本低。Mybatis3.0在整体结构上和ibatis2.X差不多,改进特性如下: 1.解析xml引进了Xpath,不像ibatis2.x那样业余 2.动态sql用OGNL解析 3.加入注解配置sql,感觉没什么特别大的用途,我更喜欢xml方式,代码和配置分离,这也是ibatis的初衷 4.加强了缓存这块的功能。Mybatis3.0把缓存模块分得更细,分为“持久实现(prepetual)”和“资源回收策略实现(eviction)”,更好的对缓存功能进行自己组合和扩展 5.终于加入的plugin功能,就像struts一样,这样就可以很好的扩展内部的Executor,,StatementHandler….等内部对象功能。 MyBatis插入时候获取自增主键方法 http://www.linuxidc.com/Linux/2014-03/98965.htm MyBatis的分页功能还是基于内存分页(查找出所有记录再取出偏移量的记录,如果jdbc驱支持absolute定位或者rs.next()到指定偏移位置),其实这样的分页实现基本没用,特别是大量数据情况下。不过我们可以通过plugin功能来扩展MyBatis的分页功能、实现物理分页。具体做法如下: 1、编写分页插件类: /** * 版权所有:华信软件 * 项目名称:ACWS框架类 * 创建者: Wangdf * 创建日期: 2014-4-2 * 文件说明: ACWS框架分页接口类 */ package framework.core.interceptor; import Java.sql.Connection; import java.util.Map; import java.util.Properties; import org.apache.commons.collections.MapUtils; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory; import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.RowBounds; import framework.core.util.DBUtil; /** * ACWS框架分页接口类 * @author Wangdf * */ @Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) }) public class PaginationInterceptor implements Interceptor { private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory(); private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory(); @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY); RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds"); if (rowBounds == null || rowBounds == RowBounds.DEFAULT) { return invocation.proceed(); } // 分离代理对象链(由于目标类可能被多个拦截器拦截,从而形成多次代理,通过下面的两次循环可以分离出最原始的的目标类) while (metaStatementHandler.hasGetter("h")) { Object object = metaStatementHandler.getValue("h"); metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY); } // 分离最后一个代理对象的目标类 while (metaStatementHandler.hasGetter("target")) { Object object = metaStatementHandler.getValue("target"); metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY); } BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql"); Object params = boundSql.getParameterObject(); if(params instanceof Map){ @SuppressWarnings("unchecked") Map<String, Object> paramsMap = (Map<String, Object>)params; MapUtils.safeAddToMap(paramsMap, "STARTROW", String.valueOf(rowBounds.getOffset())); MapUtils.safeAddToMap(paramsMap, "ENDROW", String.valueOf(rowBounds.getLimit())); } String sql = boundSql.getSql(); StringBuffer sbSql = new StringBuffer(); // 重写sql Configuration configuration = (Configuration)metaStatementHandler.getValue("delegate.configuration"); DBUtil dbUtil = new DBUtil(configuration); if(dbUtil.isMySQL()){ sbSql.append(sql).append(" LIMIT ").append(rowBounds.getOffset()-1).append(", ").append(rowBounds.getLimit()-1); metaStatementHandler.setValue("delegate.boundSql.sql", sbSql.toString()); // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); } else if(dbUtil.isOracle()){ sbSql.append("SELECT * "); sbSql.append(" FROM (SELECT ROWNUM RN, NOPAGESQL.* "); sbSql.append(" FROM (").append(sql).append(") NOPAGESQL "); sbSql.append(" WHERE ROWNUM <= ").append(rowBounds.getLimit()).append(")"); sbSql.append(" WHERE RN >= ").append(rowBounds.getOffset()); metaStateme ntHandler.setValue("delegate.boundSql.sql", sbSql.toString()); // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); } else { } // 将执行权交给下一个拦截器 return invocation.proceed(); } @Override public Object plugin(Object target) { // 当目标类是StatementHandler类型时,才包装目标类,否者直接返回目标本身,减少目标被代理的次数 if (target instanceof StatementHandler) { return Plugin.wrap(target, this); } else { return target; } } @Override public void setProperties(Properties properties) { // TODO Auto-generated method stub } } 2、配置读取类 /** * 版权所有:华信软件 * 项目名称:ACWS框架类 * 创建者: Wangdf * 创建日期: 2014-4-2 * 文件说明: ACWS框架数据库相关工具类 */ package framework.core.util; import org.apache.commons.lang.StringUtils; import org.apache.ibatis.session.Configuration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * ACWS框架数据库相关工具类 * @author Wangdf */ public class DBUtil { private static final String DBTYPE_MYSQL = "MySQL";//支持的类型:MySQL,Oracle private static final String DBTYPE_ORACLE = "Oracle";//支持的类型:MySQL,Oracle private static Logger logger = LoggerFactory.getLogger(DBUtil.class); private Configuration configuration = null; private String dbType = ""; private String defaultDateFormat = ""; public DBUtil(Configuration configuration){ if(configuration == null){ logger.error("系统启动失败:MyBatis Configuration 对象为空!"); throw new IllegalArgumentException("系统启动失败:MyBatis Configuration 对象为空!"); } this.configuration = configuration; this.dbType = this.configuration.getVariables().getProperty("dbtype"); if(StringUtils.isBlank(dbType)){ logger.error("数据库类型没有配置!"); } else { logger.info("数据库类型为:"+dbType); } this.defaultDateFormat = this.configuration.getVariables().getProperty("defaultDateFormat"); if(StringUtils.isBlank(this.defaultDateFormat)){ this.defaultDateFormat="yyyy-MM-dd"; logger.info("数据库日期默认格式字符串没有指定!系统默认为:yyyy-MM-dd"); } else { logger.info("数据库日期默认格式字符串:"+this.defaultDateFormat); } } /** * 判断是否是Oracle数据库 * @return * @author wangdf */ public boolean isOracle(){ return DBTYPE_ORACLE.equals(this.dbType); } /** * 判断是否是MySQL数据库 * @return * @author wangdf */ public boolean isMySQL(){ return DBTYPE_MYSQL.equals(this.dbType); } /** * 取得数据库类型 * @return * @author wangdf */ public String getDbType(){ return this.dbType; } /** * 取得默认日期格式 * @return * @author wangdf */ public String getDefaultDateFormat(){ return this.defaultDateFormat; } } 3、在mybatis全局配置文件设置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties> <property name="dbtype" value="MySQL"/><!-- 数据库类型:MySQL、Oracle --> <property name="defaultDateFormat" value="yyyy-MM-dd"/> </properties> <settings> <setting name="cacheEnabled" value="true" /> <setting name="lazyLoadingEnabled" value="true" /> <setting name="multipleResultSetsEnabled" value="true" /> <setting name="useColumnLabel" value="true" /> <setting name="defaultExecutorType" value="REUSE" /> <setting name="defaultStatementTimeout" value="25000" /> </settings> <plugins> <plugin interceptor="framework.core.interceptor.PaginationInterceptor"></plugin> </plugins> </configuration> (编辑:东莞站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |