精华内容
下载资源
问答
  • mybatis分页

    2018-05-19 22:48:48
    mybatis分页完整版,利用sql在动态sql语句,配置的spring,springmvc,mybatis,数据库改成自己的。并且改下自己配置
  • mybatis 分页

    2017-05-24 11:26:37
    mybatis分页

    mybatis分页

    展开全文
  • Mybatis分页插件-PageHelper的使用

    万次阅读 多人点赞 2016-03-03 20:19:34
    Mybatis分页插件-PageHelper的使用怎样配置mybatis这里就不提了,我来说说我配置这个分页插件的过程吧。下载JAR包分页插件pagehelper.jar:...

    #Mybatis分页插件-PageHelper的使用

    怎样配置mybatis这里就不提了,我来说说我配置这个分页插件的过程吧。

    下载JAR包

    分页插件pagehelper.jar:

    https://oss.sonatype.org/content/repositories/releases/com/github/pagehelper/pagehelper/
    http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/
    由于使用了sql解析工具,你还需要下载jsqlparser.jar

    4.1.0及以后版本需要0.9.4版本

    http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/0.9.4/
    4.1.0以前版本需要0.9.1版本

    http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/0.9.1/

    一、首先,在spring-mybatis.xml中是这样配置:

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="mapperLocations" value="classpath:com/sinyat/api/weather/mapping/*.xml" />
    		<property name="typeAliasesPackage" value="com.sinyat.api.weather.model" />
    		<property name="plugins">
    			<array>
    				<bean class="com.github.pagehelper.PageHelper">
    					<property name="properties">
    						<value>
    							dialect=mysql
    						</value>
    					</property>
    				</bean>
    			</array>
    		</property>
    	</bean>
    

    我是在spring里配置的,还可以在mybatis-config.xml里配置,有兴趣的话可以百度下。

    二、需要分页,自然就还要一个查询了。用了PageHelper之后,查询语句就可以很简单了。

    <select id="selectAll" resultMap="BaseResultMap">
      	select
      	<include refid="Base_Column_List" />
      	from citylist
      </select>
    

    这是我的查询语句,查询城市列表。没有其他条件,就是查所有。当然,我这只是一个小的demo,没做那么麻烦,真正的使用,是需要条件查询的。
    现在来讲讲用了PageHelper之后的好处:
    那就是查询语句可以不用limit,但是就一点好处吗?自然不是。请接着往下看。

    三、接口、实现类我就不再贴代码了,该怎么写还是怎么写,不需要传分页参数。然后是Controller:

    @RequestMapping("showcity")
    	public ModelAndView showCityList(ModelAndView mv,
    			@RequestParam(required=true,defaultValue="1") Integer page,
    			@RequestParam(required=false,defaultValue="10") Integer pageSize){
    		
    		PageHelper.startPage(page, pageSize);
    		List<CityList> list = cityListService.selectAll();
    		
    		PageInfo<CityList> p=new PageInfo<CityList>(list);
    		//System.out.println(p.getList());
    		
    		mv.addObject("citylist", list);
    		mv.addObject("page", p);
    		mv.setViewName("weather/showCityList");
    		
    		return mv;
    	}
    

    可以看到,方法里有两个参数,前面也说了,这是一个demo,仅仅只是一个非常简单的分页效果。

    PageHelper.startPage(page, pageSize);
    

    这段代码表示,程序开始分页了,page默认值是1,pageSize默认是10,意思是从第1页开始,每页显示10条记录。

    PageInfo这个类是插件里的类,这个类里面的属性还是值得看一看:

    	//当前页
        private int pageNum;
        //每页的数量
        private int pageSize;
        //当前页的数量
        private int size;
        //排序
        private String orderBy;
    
        //由于startRow和endRow不常用,这里说个具体的用法
        //可以在页面中"显示startRow到endRow 共size条数据"
    
        //当前页面第一个元素在数据库中的行号
        private int startRow;
        //当前页面最后一个元素在数据库中的行号
        private int endRow;
        //总记录数
        private long total;
        //总页数
        private int pages;
        //结果集
        private List<T> list;
    
        //第一页
        private int firstPage;
        //前一页
        private int prePage;
        //下一页
        private int nextPage;
        //最后一页
        private int lastPage;
    
        //是否为第一页
        private boolean isFirstPage = false;
        //是否为最后一页
        private boolean isLastPage = false;
        //是否有前一页
        private boolean hasPreviousPage = false;
        //是否有下一页
        private boolean hasNextPage = false;
        //导航页码数
        private int navigatePages;
        //所有导航页号
        private int[] navigatepageNums;
    

    使用PageInfo这个类,你需要将查询出来的list放进去:

    PageInfo<CityList> p=new PageInfo<CityList>(list);
    

    然后mv.addObject("page", p);
    这样在页面中就可以通过${page.nextPage}翻到下一页,
    ${page.prePage}翻到上一页,
    列表

    下面这个是因为我没有进行判断,所以,第0页自然是什么都没有的。
    这里写图片描述
    判断的话,在PageInfo里有对应的属性,比如:

    	//是否有前一页
        private boolean hasPreviousPage = false;
        //是否有下一页
        private boolean hasNextPage = false;
    

    好了,demo就是这些了。

    下一个是通用Mapper,据说也是很不错的东西。

    在这里插入图片描述

    展开全文
  • mybatis 分页详解、mybatis分页查询,mybatis分页拦截器使用、struts2下mybatis分页   mybatis默认是支持分页的,内部通过创建可滚动的ResultSet(ResultSet.TYPE_FORWARD_ONLY)对结果集指针进行跳转以达到分页...

              mybatis 分页详解、mybatis分页查询,mybatis分页拦截器使用、struts2下mybatis分页

     


    mybatis默认是支持分页的,内部通过创建可滚动的ResultSet(ResultSet.TYPE_FORWARD_ONLY)对结果集指针进行跳转以达到分页控制的目的。实际使用,需要传入RowBounds类型参数来告知mybatis做分页控制,RowBounds构造器有两个参数:

    RowBounds(int offset, int limit), offset,从第offset条开始查(起始于0),limit查询个数。如:

    RowBounds(0, 11):第一页,显示十一条【0-10】、

    RowBounds(11, 10):第二页,显示十一条【11-21】

    。。。。

    不过mybatis默认分页存在两个问题:1.通过ResultSet控制指针进行分页与数据库本身通过sql语句进行分页相比,查询性能欠佳。2.无法返回总记录数,通常情况下前端表格除了要显示第n页数据,也需要显示总记录数,通过内置RowBounds显然不能满足需求。

    有些兄弟可能不知道怎么使用,没关系,我先做一个简单的示例,供参考。

    问题:现有区号表一张,需要支持表分页查询:

    1.定义区号javabean AreaCode.java:

    AreaCode.java

    public class AreaCode implements Serializable{
            //javabean与数据库字段一致
    	private String provId;
    	
    	private String description;
    	
    	public AreaCode() {
    		super();
    	}
    
    	public String getProvId() {
    		return provId;
    	}
    
    	public void setProvId(String provId) {
    		this.provId = provId;
    	}
    
    	public String getDescription() {
    		return description;
    	}
    
    	public void setDescription(String description) {
    		this.description = description;
    	}
    
    	
    
    }

    2.定义mapper接口AreaCodeMapper.java(为了简单只定义一个查询接口):

    public interface AreaCodeMapper {
    	//这个方法不支持分页,是全查
            public List<AreaCode> list();
            
            //通过RowBounds参数告知mybatis此方法需要分页查询
    	public List<AreaCode> list(RowBounds rowBounds);
    	
    }

    3.定义配置文件AreaCodeMapper.xml(配置仅供参考):

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="AreaCodeMapper">
    	<select id="list" resultType="AreaCode">
    		select provId, description from areacodecfg
    	</select>
    </mapper>
    

    4.定义配置文件configuration.xml(配置仅供参考):

    <?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>
    	<environments default="development">
    		<environment id="development">
    			<transactionManager type="JDBC" />
    			<dataSource type="UNPOOLED">
                                    <!-- ${driver}为实际的数据库驱动名 -->
    				<property name="driver" value="${driver}" />
    				<property name="url" value="${url}" />
    				<property name="username" value="${username}" />
    				<property name="password" value="${password}" />
    			</dataSource>
    		</environment>
    	</environments>
    	<mappers>
                    <!-- 添加mapper文件 -->
    		<mapper resource="AreaCodeMapper.xml" />
    	</mappers>
    </configuration>

    5.测试:

    public static void main(String[] args) throws SQLException {
    		Reader reader = null;
    		SqlSessionFactory sf;
    		SqlSession session = null;
    		try {
    			SqlSessionFactoryBuilder build = new SqlSessionFactoryBuilder();
                            //根据配置文件生成SqlSessionFactory
    			reader = Resources.getResourceAsReader("test/configuration.xml");
    			sf = build.build(reader);
    			session = sf.openSession();
    			AreaCodeMapper mapper = session.getMapper(AreaCodeMapper.class);
                            //查询第一页,每页十条记录
    			RowBounds rowBounds = new RowBounds(0, 10);
    			List<AreaCode> list = mapper.list(rowBounds);
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			if (reader != null) {
    				try {
    					reader.close();
    				} catch (IOException e) {
    				}
    			}
    			if (session != null) {
    				session.close();
    			}
    		}
    	}

    分页查询已搞定,但以上查询并不包含总记录数,这个比较麻烦,如果你愿意,再添加一个总记录数查询的接口,不愿意接着往下看。

    下面通过扩展RowBounds,使其支持数据库分页与总记录数统计。

    1.由于不同的数据库,分页sql语句略有不同,我们通过一个枚举类型DBType.java,用于区分不同数据库类型。假设只支持mysql和oracle两种数据库,要添加其他数据库,自己扩展:

    public enum DBType {
    	MYSQL, ORACLE
    }

    2.创建用于sql转换的接口IDialect.java。接口功能:可将普通查询sql,转换成与具体数据库相关的分页查询sql,IDialect.java:

    public interface IDialect {
            //支持根据字段进行排序查询,留给读者实现吧
    	String getSortSQL(String sql, List<String> sortFields, List<String> sortOrders);
    
            //根据原始查询sql生成与数据库相关的查询sql
            //原始sql就是上文提到的:select provId, description from areacodecfg
    	String getLimitSQL(String sql, int offset, int limit);
    
            //根据原始的sql生成查询总记录数的sql
    	String getTotalSQL(String sql);
    }
    

    3.定义IDialect的抽象实现ADialect.java:

     

    public abstract class ADialect implements IDialect {
    
    	@Override
    	public String getTotalSQL(String sql) {//基本所有数据库通用
    		StringBuffer totalSql = new StringBuffer(sql.length() + 100);
    		totalSql.append("select count(0) from ( ").append(sql).append(
    				" ) as _tmp_count");
    		return totalSql.toString();
    	}
    }

    4.定义mysql的实现:

    public class MySqlDialect extends ADialect {
    
    	@Override
    	public String getLimitSQL(String sql, int offset, int limit) {
    		sql = sql.trim();
    		StringBuffer newSql = new StringBuffer(sql.length() + 100);
    		newSql.append("select * from (").append(sql).append(
    				") as _tmp_query limit ").append(offset).append(",").append(limit);
    
    		return newSql.toString();
    	}
    }
    

    5.定义oracle的实现:

    public class OracleDialect extends ADialect {
    
    	@Override
    	public String getLimitSQL(String sql, int offset, int limit) {
    		sql = sql.trim();
    		StringBuffer pageSelect = new StringBuffer(sql.length() + 100);
    		pageSelect
    				.append("select * from ( select row_.*, rownum rownum_ from ( ");
    		pageSelect.append(sql);
    		pageSelect.append(" ) row_ ) where rownum_ > ").append(offset).append(
    				" and rownum_ <= ").append(offset + limit);
    
    		return pageSelect.toString();
    	}
    }
    

    5.创建IDialect的实例化工厂RoutingDialect.java:

    public class RoutingDialect implements IDialect {
            //实际委托给delegate
    	private IDialect delegate;
            //用于缓存实例
    	private static Map<DBType, IDialect> dialectMap = new HashMap<DBType, IDialect>();
    	
    	private RoutingDialect(DBType dbType) {
    		switch (dbType) {
    		case MYSQL:
    			delegate = new MySqlDialect();
    			break;
    		case ORACLE:
    			delegate = new OracleDialect();
    			break;
    		default:
    			delegate = new MySqlDialect();
    		}
    	}
            
            //工厂方法,根据数据库类型返回相应的Dialect
    	public static IDialect getDialect(DBType dbType) {
    		IDialect dialect = null;
    		dialect = dialectMap.get(dbType);
    		if (dialect == null) {
    			synchronized (dialectMap) {
    				dialect = dialectMap.get(dbType);
    				if (dialect == null) {
    					dialect = new RoutingDialect(dbType);
    					dialectMap.put(dbType, dialect);
    				}
    			}
    		}
    		return dialect;
    	}
    	
    	@Override
    	public String getLimitSQL(String sql, int offset, int limit) {
    		return delegate.getLimitSQL(sql, offset, limit);
    	}
    
    	@Override
    	public String getTotalSQL(String sql) {
    		return delegate.getTotalSQL(sql);
    	}
    
    }

    6.创建SmartRowBounds扩展自RowBounds,支持数据库分页,与总记录数统计:

    public class SmartRowBounds extends RowBounds {
    	
    	//内部参数:当前查询记录的偏移
    	private int queryOffset = -1;
    	
    	//内部参数:当前查询记录的条数
    	private int queryLimit = -1;
    	
    	//内部参数:用于保存总记录数
    	private int totalCount;
    	
    	//是否使用数据库分页,还是使用mybatis的默认滚动分页
    	private boolean isDbSupport = false;
    	
    	//内部标识,是否阻止默认分页,当isDbSupport=true时此标识必须设成true
    	private boolean preventDefaultRowBounds = false;
    	
    	public SmartRowBounds() {
                    //无分页参数,不分页
    		super(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT);
    	}
    	
    	public SmartRowBounds(int queryOffset, int queryLimit) {
                    //将分页参数传递给父类,这一点很重要,可用于默认分页
    		super(queryOffset, queryLimit);
    		this.queryOffset = queryOffset;
    		this.queryLimit = queryLimit;
    	}
    
    	public SmartRowBounds(int queryOffset, int queryLimit,
    			boolean isDbSupport) {
    		this(queryOffset, queryLimit);
    		this.isDbSupport = isDbSupport;
    	}
    	
            //根据数据库类型,即原始的查询sql来生成数据库相关的分页sql,
            //委托IDialect进行转换
    	public String getPageSql(DBType dbType, String rawSql) {
    		IDialect dialet = RoutingDialect.getDialect(dbType);
                    //只有使用数据库分页的情况下才会对sql进行数据库相关的转换
    		if (isDbSupport && queryOffset >= 0 && queryLimit >= 0) {
    			rawSql = dialet.getLimitSQL(rawSql, queryOffset, queryLimit);
    			//如果使用了数据库分页,就必须阻止mybatis默认分页行为。
    			//设置一个阻止默认分页的标识preventDefaultRowBounds=tue
    			preventDefaultRowBounds = true;
    		}
    		return rawSql;
    	}
    
    	public String getTotalSQL(DBType dbType, String rawSql) {
    		 return RoutingDialect.getDialect(dbType).getTotalSQL(rawSql);
    	}
    	
    	public void setTotalCount(int totalCount) {
    		this.totalCount = totalCount;
    	}
    
    	
    	public int getTotalCount() {
    		return totalCount;
    	}
    
    	@Override
    	public int getLimit() {
                    //mysql会调用RowBounds的getLimit方法计算查询记录条数,
                    //如果未使用数据库分页,你需要告诉mybatis查询的记录长度queryLimit
    		if (!preventDefaultRowBounds) {
    			return queryLimit;
    		}
    		//如果你使用了数据库分页,那么mybatis内部就不能再使用ResultSet滚动分页了
    		//因此需要返回super.NO_ROW_LIMIT,告知mybatis不进行分页相关的结果集指针跳转
    		return super.NO_ROW_LIMIT;
    	}
    
    
    	@Override
    	public int getOffset() {
                    //mysql会调用RowBounds的getOffset方法计算查询偏移,
    		if (!preventDefaultRowBounds) {
    			return queryOffset;
    		}
    		//如果默认使用了数据库分页,那么mybatis内部就不能再使用ResultSet滚动分页了
    		//因此返回NO_ROW_OFFSET
    		return super.NO_ROW_OFFSET;
    	}
    
    	public void reset() {
    		totalCount = 0;
    		preventDefaultRowBounds = false;
    	}
    
    }

    7.创建mybatis分页拦截器类:

    //注意注解,这里只对Connection创建的的preparedStatement进行拦截,固定写法,可以不深究
    @Intercepts( { @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
    public class PageStatementInterceptor implements Interceptor {
    
    	private DBType dbType;
    
    	public void setDBType(String dbTypeStr) {
    		if (dbTypeStr != null && !"".equals(dbTypeStr.trim())) {
    			try {
    				this.dbType = DBType.valueOf(dbTypeStr.trim().toUpperCase());
    			} catch (Exception e) {
    				this.dbType = DBType.MYSQL;
    			}
    		}
    	}
    
            //mybatis框架自动调用
            @Override
    	public void setProperties(Properties properties) {
    		setDBType(properties.getProperty("DBType"));
    	}
    
    	@Override
    	public Object intercept(Invocation invocation) throws Throwable {
    		try {
    			StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
    			StatementHandler deleStatementHandler = (StatementHandler) getFieldValue(statementHandler, "delegate");
    			RowBounds rowBounds = (RowBounds) getFieldValue(deleStatementHandler, "rowBounds");
    			MappedStatement mappedStatement = (MappedStatement)getFieldValue(deleStatementHandler, "mappedStatement");
    			//只针对select类型切分页参数是SmartRowBounds的查询进行sql改造
    			if (rowBounds != null && mappedStatement != null && 
    					SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType()) && 
    					SmartRowBounds.class.isAssignableFrom(rowBounds.getClass())) {
    				SmartRowBounds pageHandler = (SmartRowBounds) rowBounds;
    				//获取原始sql
    				BoundSql boundSql = statementHandler.getBoundSql();
    				if (boundSql != null) {
    					//进行总记录数查询
    					countTotal(pageHandler, (Connection) invocation.getArgs()[0], statementHandler.getParameterHandler(), boundSql.getSql());
    					//将原始sql替换为支持分页的sql
    					setFieldValue(boundSql, "sql", pageHandler.getPageSql(dbType, boundSql.getSql()));
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return invocation.proceed();
    	}
    
    	private Field getField(Object target, String fieldName) {
    		Field field = null;
    		for (Class<?> clazz = target.getClass(); clazz != Object.class; clazz = clazz
    				.getSuperclass()) {
    			try {
    				field = clazz.getDeclaredField(fieldName);
    				break;
    			} catch (NoSuchFieldException e) {
    				// ignore
    			}
    		}
    		if (field != null) {
    			if (!field.isAccessible()) {
    				try {
    					field.setAccessible(true);
    				} catch (Exception e) {
    					// ignore
    				}
    			}
    		}
    		return field;
    	}
    	
    	private Object getFieldValue(Object target, String fieldName) {
    		try {
    			Field field = getField(target, fieldName);
    			if (field != null) {
    				return field.get(target);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    	
    	private void setFieldValue(Object target, String fieldName, Object value) {
    		try {
    			Field field = getField(target, fieldName);
    			if (field != null) {
    				field.set(target, value);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    	
    	private void countTotal(SmartRowBounds pageHandler, Connection con, ParameterHandler paramHandler, String rawSql) {
    		ResultSet rs = null;
    		PreparedStatement stmt = null;
    		try {
    			String totalSql = pageHandler.getTotalSQL(dbType, rawSql);
    			if (totalSql != null && !totalSql.isEmpty()) {
    				stmt = con.prepareStatement(totalSql);
    				paramHandler.setParameters(stmt);
    				rs = stmt.executeQuery();
    				if (rs.next()) {
    					pageHandler.setTotalCount(rs.getInt(1));
    				}
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		} finally {
    			try {
    				if (rs != null) {
    					rs.close();
    				}
    			} catch (SQLException e1) {
    				// ignore
    			}
    			try {
    				if (stmt != null) {
    					stmt.close();
    				}
    			} catch (Exception e) {
    				// ignore
    			}
    		}
    	}
    	
    	@Override
    	public Object plugin(Object target) {
    		return Plugin.wrap(target, this);
    	}
    
    }

    8.configuration.xml添加拦截器配置:

    <plugins>
    		<plugin interceptor="PageStatementInterceptor">
    			<property name="DBType" value="mysql" />
    		</plugin>
    	</plugins>

    9.测试:

    public class Test {
    	
    	
    	
    	public static void main(String[] args) throws SQLException {
    		Reader reader = null;
    		SqlSessionFactory sf;
    		SqlSession session = null;
    		try {
    			SqlSessionFactoryBuilder build = new SqlSessionFactoryBuilder();
    			reader = Resources.getResourceAsReader("test/configuration.xml");
    			sf = build.build(reader);
    			session = sf.openSession();
    			AreaCodeMapper mapper = session.getMapper(AreaCodeMapper.class);
    			SmartRowBounds rowBounds = new SmartRowBounds(0, 10, true);
                            //分页记录与记录总数,使用一次接口调用搞定
    			List<AreaCode> list = mapper.list(rowBounds);
    			int total = rowBounds.getTotalCount();
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			if (reader != null) {
    				try {
    					reader.close();
    				} catch (IOException e) {
    				}
    			}
    			if (session != null) {
    				session.close();
    			}
    		}
    	}
    }

    以上介绍了拦截器分页的基本用法,下面简单介绍下,如果配合struts, spring进行分页查询

    1.创建业务类AreaCodeService.java,正常情况下应该创建业务接口再创建实现类,为了简单起见,跳过接口创建:

    @Service
    public class AreaCodeService {
    	//通过spring进行自动注入
    	@Resource
    	private AreaCodeMapper mapper;
    	
    	public List<AreaCode> listAreaCode(RowBounds rowBounds) {//方法1
    		
    		return mapper.list(rowBounds));
    		
    	}
    	
    	public List<AreaCode> listAreaCode(int offset, int limit) {//方法2
    		//直接创建SmartRowBounds
    		//但是总记录数如何传递出去?
    		return mapper.list(new SmartRowBounds(offset, limit));
    		
    	}
    }

    AreaCodeService很简单,基本就是委托mapper查询,唯一需要做的就是实例化RowBounds交给mapper。

    上面代码定义了两个用于分页查询的方法,方法1:通过传入RowBounds类型参数,实现分页控制,好处是简单,实际的rowbounds对象的创建代码放到调用者(一般是structs的控制器对象)中,缺点是AreaCodeService与mybatis耦合太紧,如果以后使用其他orm框架如hibernate,那就需要修改service类。方法2:方法独立性比较好,不与任何特定框架耦合,它只关心查询偏移,与返回记录数,但问题是,方法的返回类型是List<AreaCode>, 如何将SmartRowBounds的总记录数返回给调用者对象?先不说,后面再谈!

    2.创建Struts控制器的抽象Action, AbstractAction.java:

    public class AbstractAction extends ActionSupport{
    	
    	public static final String JSON = "json";
    	
    	//querOffset与queryLimit是通过前台jsp传过来的分页相关参数
    	//其实可以将这两个参数封装成Page对象,通过Page对象来取queryOffset与queryLimit
    	//这里这样操作是为了偷懒,展示用
    	protected int queryOffset = -1;
    	
    	protected int queryLimit = -1;
    	
    	//前台页表格加载需要的数据对象
    	protected Object gridDataList;
    	
    	//将分页的查询的结果存放到gridDataList
    	//最终通过struts.xml配置文件将gridDataList转换为json传到前台jsp
    	//list为查询的结果, total为总记录数
    	protected void setJsonGrid(List list, int total) {
            Map data = new HashMap();
            data.put("total", total);
            data.put("rows", list);
            this.gridDataList = data;
        }
    
    	public int getQueryOffset() {
    		return queryOffset;
    	}
    
    	public void setQueryOffset(int queryOffset) {
    		this.queryOffset = queryOffset;
    	}
    
            public int getGridDataList() {
    		return gridDataList;
    	}
    
    	public void setGridDataList(Object gridDataList) {
    		this.gridDataList= gridDataList;
    	}
    
    	public int getQueryLimit() {
    		return queryLimit;
    	}
    
    	public void setQueryLimit(int queryLimit) {
    		this.queryLimit = queryLimit;
    	}
    }

    抽象action继承自Struts的ActionSupport,方法功能看注释,不废话了。

    2.创建具体控制器AreaCodeAction.java:

    public class AreaCodeAction extends AbstractAction{
    	//通过spring将AreaCodeService注入进来
    	@Resource
    	private AreaCodeService service;
    	public String gridList() {
    		SmartRowBounds rb = new SmartRowBounds(queryOffset, queryLimit, true);
    		List<AreaCode> list = service.listAreaCode(rb);//使用AreaCodeService的方法1
    		setJsonGrid(list, rb.getTotalCount());
    		return JSON;
    	}
    }

    只有一个gridList ()方法,通过前台页面传进来的分页参数创建SmartRowBounds交给service进行分页查询,查询完了会通过rb回取总记录数,一起交给父类的setJsonGrid()方法。

    上文提到的,将控制器属性gridDataList转化为json对象传到前台jsp,需要在struct.xml中加一段配置,内容片段如下:

    <global-results>
        <result name="json" type="json">
    	<param name="root">gridDataList</param>
        </result>
    </global-results>

    spring中mybatis拦截器配置片段:

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="xx" />
            <property name="plugins">
            	<array>
                        <!--拦截器类全称-->
            	    <bean class="PageStatementInterceptor"></bean>
            	</array>
            </property>
    </bean>

    自此所有内容已叙完,最后继续探讨下前面的遗留问题,AreaCodeService的方法2,

    如何将查询总数返回到控制器?

    其实至少有两个方法:

    1.List<AreaCode> listAreaCode(int offset, int limit)再增加第三个参数,然后将SmartRowBounds的记录总数放到第三个参数中,供控制器取,以下是模拟实现:

    public List<AreaCode> listAreaCode(int offset, int limit, ResultHook hook) {//方法2
    		SmartRowBounds rb = new SmartRowBounds(offset, limit);
    		try {
    			
    			return mapper.list(new SmartRowBounds(offset, limit,true));
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			//将记录总数传给hook,通知到控制器去取
    			hook.setResult(rb.getTotalCount());
    		}
    		
    	}
    }

     2.借助线程本地上下文ThreadLocal,同一个线程总能共享相同的数据对象,创建RowBoundsHolder对象:

    public class RowBoundsHolder {
    	
    	private static ThreadLocal<SmartRowBounds> rowBoundHolder = new ThreadLocal<SmartRowBounds>();
    	
    	public static SmartRowBoundsinstance(int offset, int limit) {
    		SmartRowBounds rb = new SmartRowBounds(offset, limit);
    		rowBoundHolder.set(rb);
    		return rb;
    	}
    	
    	public static SmartRowBounds instance(int offset, int limit, boolean supportDbPage) {
    		SmartRowBounds rb = new SmartRowBounds(offset, limit, supportDbPage);
    		rowBoundHolder.set(rb);
    		return rb;
    	}
    	
    	public static SmartRowBoundsget() {
    		return rowBoundHolder.get();
    	}
    }

     RowBoundsHolder的instance方法创建一个SmartRowBounds rb并设置到线程本地山下文中,在同一个线程中,调用任意对象的任意方法,总能访问此rb对象的引用。

    改造AreaCodeService的方法2:

    @Service
    public class AreaCodeService {
    	//通过spring进行自动注入
    	@Resource
    	private AreaCodeMapper mapper;
    	
    	public List<AreaCode> listAreaCode(int offset, int limit) {//方法2
    		return mapper.list(RowBoundsHolder.instance(offset, limit, true));
    		
    	}
    }

     改造AbstractAction添加新方法:

    protected void setJsonGrid(List list) {
    		int total = list == null ? 0 : list.size();
    		SmartRowBounds rb = RowBoundsHolder.get();
    		if (rb != null) {//通线程上下文获取总记录数
    			total = rb.getTotalCount();
    		}
            Map data = new HashMap();
            data.put("total", total);
            data.put("rows", list);
            this.gridDataList = data;
        }

    修改AreaCodeAction.java:

    public class AreaCodeAction extends AbstractAction{
    	//通过spring将AreaCodeService注入进来
    	@Resource
    	private AreaCodeService service;
    	public String gridList() {
    		List<AreaCode> list = service.listAreaCode(queryOffset, queryLimit);//使用AreaCodeService的方法2
    		setJsonGrid(list);
    		return JSON;
    	}
    }

     All right,如果你觉得有“点”帮助,请点个“赞”哦,3q。

    以上实现仅供参考,思路各异,满意就行。

    原创博文,转载请注明出处。

    展开全文
  • MyBatis 分页

    2015-06-08 11:02:17
    MyBatis 物理分页,支持SQL Server 2005、2008,并且支持Oralce,MySQL. 非常好用的分页框架,只需一句代码,就可以进行物理分页
  • MyBatis分页

    2019-04-19 01:12:47
    NULL 博文链接:https://mylittlefairy2010.iteye.com/blog/1851692
  • Mybatis分页插件

    2020-12-20 09:11:08
    Mybatis分页插件
  • mybatis分页插件

    2019-01-17 19:17:20
    mybatis分页插件
  • mybatis分页查询

    千次下载 热门讨论 2015-12-28 00:04:59
    mybatis分页查询,spring + maven + mybatis实现分页查询源码
  • mybatis分页源码

    2017-11-03 17:02:21
    mybatis分页源码
  • Mybatis自带的两种分页方法Mybatis有两种自带分页方法:RowBounds和PageHelper,其中前者是逻辑分页,后者是物理分页。(本文后续假设使用myabtis-generator生成mapper)RowBoundsRowBounds方法有两个入参:offset和...

    c3938ca70626c51e2bbb52e02ee3cdf8.png

    Mybatis自带的两种分页方法

    Mybatis有两种自带分页方法:RowBounds和PageHelper,其中前者是逻辑分页,后者是物理分页。(本文后续假设使用myabtis-generator生成mapper)

    RowBounds

    RowBounds方法有两个入参:offset和limit。它的实现是逻辑分页,即先一次性获取所有resultSet,然后从offset位置开始截取limit条记录,丢弃其它记录。

    这种方式的优点是使用简单方便,但是性能差,因为每次是查询所有数据后进行截取。

    使用方法:

    新添加一个手写的HandwriteMapper.xml,在里面添加一条新的sql

    <select 

    ResultMapper.java

    List

    实际调用:

    // 0,100换成你的参数
    

    PageHelper

    PageHelper是Mybatis开源的第三方插件,详情见官方文档:

    如何使用分页插件pagehelper.github.io

    这种方法的优点:使用物理分页,因此性能比上面的方法更好;调用也很方便

    结论

    大数据量的情况下推荐PageHelper,小数据量可以使用RowBounds

    当然也可以使用原生的sql语句进行分页,但是那样略微繁琐,本文提出的方案已经可以满足日常需求(其实是懒得写了hhh)


    碰到的bug!(划重点)

    作者在使用RowBounds时碰到一个奇怪的bug。在对数据库数据分批次进行分页查询时,发现从第二页开始数据量为0,至今仍不知原因……既然如此,用pageHelper不香吗(手动狗头

    展开全文
  • 今天来跟大家分享一下MyBatis分页插件。MyBatis的一个分页插件叫PageHelper,虽然没有那么的强大(我在最后会说明它的缺点),但还是挺不错的。我们知道,在mysql中,分页的sql是使用limit来做,如果我们自己写sql,...
  • Mybatis分页插件 - PageHelper如果你也在用Mybatis,建议尝试该分页插件,这一定是最方便使用的分页插件。该插件目前支持以下数据库的物理分页:OracleMysqlMariaDBSQLiteHsqldbPostgreSQLDB2SqlServer(2005+)...
  • MyBatis,作为目前流行的ORM框架,大大方便了日常开发。...这里将介绍如何在Spring Boot、MyBatis的环境中通过MyBatis PageHelper高效方便的实现分页查询配置1. 添加Maven依赖<!--MyBatis 分页插件: MyBat...
  • mybatis 分页代码

    2016-03-08 15:18:08
    mybatis 分页代码 基于内存分页 有需要的同学看看吧
  • 隔了大半年终于发布了一个小版本,升级了一些依赖,解决了一些兼容性问题和 BUG,升级...5.1.9 - 2019-05-29升级 jsqlparser 为 2.0,升级 mybatis 为 3.5.1,解决兼容性问题。完善分页逻辑判断,fixed #389解决 Met...
  • MyBatis 分页源码简单

    2017-07-17 10:27:57
    MyBatis 分页源码简单
  • 分页插件pageHelper也是一个很重要的插件,本文主要和大家介绍mybatis分页插件pageHelper详解及简单实例的相关资料,需要的朋友可以参考下,希望能帮助到大家。mybatis分页插件pageHelper详解及简单实例工作的框架...
  • Mybatis分页

    千次阅读 2012-11-27 09:23:21
    众所周知,Mybatis本身没有提供基于数据库方言的分页功能,而是基于JDBC的游标分页,很容易出现性能问题。网上有很多分页的解决方案,不外乎是基于Mybatis本机的插件机制,通过拦截Sql做分页。但是在像Oracle这样的...
  • Mybatis分页插件PageHelper的jar文件,Mybatis分页插件PageHelper的jar文件,Mybatis分页插件PageHelper的jar文件 4.1.4版本
  • mybatis分页配置

    2014-12-10 20:53:43
    mybatis分页的配置方法,可以实现物理分页
  • mybatis分页插件pagehelper5.1.3,在mybatis查询中使用分页简单多了
  • mybatis分页插件源码

    2017-04-23 20:27:55
    mybatis分页插件源码,非入侵式
  • mybatis分页共享

    2015-04-11 12:27:25
    mybatis分页共享,本资源基于插件机制,通过拦截StatementHandler重写sql语句,实现数据库的物理分页。基于mybatis3.2.2开发,使用时注意版本。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,938
精华内容 7,575
关键字:

mybatis分页