数据库:mysql5.7
分页查询主要用到的还是limit
limit 10,2 查询从第11条开始的后两条,即查询结果为11,12
limit 10 查询前10条
limit 10,0 查询第11条开始后0条,即结果为0
limit 10,-1 查询第11条开始后所有记录(早期版本支持,比较新的版本可以设置第二个参数为一个很大的值)
第一种方式,自定义分页查询
(1)工具类
package com.lzy.util;public class FenyeParam { private String field; private Integer start=0,count=0; public void setField(String[] fields) { this.field=""; for(String f:fields) { this.field+=f+","; } //抹掉最后的逗号 this.field=this.field.substring(0, this.field.length()-1); } public void setField1(String sqlFields) { //like "field,field2,field3..." this.field=sqlFields; } public void setStart(Integer start) { this.start=start; } public void setCount(Integer count) { this.count=count; } public String getField() { return this.field; } public Integer getStart() { return this.start; } public Integer getCount() { return this.count; } @Override public String toString() { return "FenyeParam [field=" + field + ", start=" + start + ", count=" + count + "]"; } }
自定义了一个分页参数类FenyeParam:
field参数为查询的字段,start为开始位置,count为查询记录条数;
field参数设置提供两种方法,setField(String[])方法接收数组,自动拼接sql查询字段;setField1(String)接收String字符串,为sql字段样式(例:"id,name,sex");
(2)相关mapper.xml文件配置:
mybatis中${}和#{}区别:
${}为原样输入,不会修改或转义字符串
#{}为字符串类型输入,根据PreparedStatement安全设置参数
扩充:
PreparedStatement为JDBC sql预处理,替换对应sql字符串中的?,安全,如下代码比较直观:
package sdfadf;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class JDBCUtil { public static void main(String[] args) { try { Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testpq?characterEncoding=utf8&useSSL=true&serverTimezone=UTC","xxx","xxxxxx"); String sql="select id,name from user where id=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, "11"); ResultSet rs = ps.executeQuery(); while(rs.next()) { System.out.println(rs.getString("id")+","+rs.getString("name")); } rs.close(); ps.close(); conn.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } }}
本文用的是mysql5.7,Driver和url根据需自己版本
(3)调用(没有写完完整的controller层和service层,只完成了dao层和mapper.xml,这里的测试用的是junit的单元测试)
package com.lzy.test;import java.util.List;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.lzy.bean.User;import com.lzy.dao.UserMapper;import com.lzy.util.FenyeParam;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations= {"classpath:applicationContext.xml"})public class MyTest { @Autowired UserMapper uMapper; @Test public void Test2() { FenyeParam fenyeParam=new FenyeParam(); String[] fields=new String[] {"id","name"}; fenyeParam.setField(fields); //fenyeParam.setField1("id,name"); fenyeParam.setStart(10); fenyeParam.setCount(2); Listuser = uMapper.selectFenYe(fenyeParam); System.out.println(user); } }
结果:
第二种方式,MyBatis分页插件PageHelper的使用
1、pom加入PageHelper依赖关系
com.github.pagehelper pagehelper 5.1.8
2、配置PageHelper
配置PageHelper有在MyBatis配置文件中配置和在Spring配置文件中配置两种方式,详情请参考官方说明:
本次采用Mybatis配置文件mybatis-config.xml中配置的方式,只需要在mybatis配置文件中加入PageInterceptor,具体如下:
没有特殊要求如上即可,具体配置参考官方地址:
3、使用
PageHelper.startPage(pageNum, pageSize)方法后的第一个查询方法就会进行分页查询,故这里只需要将调用查询的方法放到PageHelper.startPage(pageNum, pageSize)方法之后就行。例如下在controller层使用PageHelper.startPage(pageNum, pageSize)对调用service层的查询方法进行分页查询:
package com.lzy.controller;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import com.github.pagehelper.PageHelper;import com.github.pagehelper.PageInfo;import com.lzy.bean.User;import com.lzy.service.TPQService;@Controllerpublic class TPQController { @Autowired TPQService tService; @ResponseBody @RequestMapping("/tpq") public PageInfoTpq() { PageHelper.startPage(10, 2); List list = tService.selectPQ(); System.out.println(list); PageInfo pu=new PageInfo<>(list); System.out.println(pu); return pu; } }
package com.lzy.service;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.lzy.bean.User;import com.lzy.bean.UserExample;import com.lzy.dao.UserMapper;@Servicepublic class TPQService { @Autowired UserMapper uMapper; public ListselectPQ() { UserExample example=new UserExample(); return uMapper.selectByExample(example); }}
查询结果:
下方PageInfo具体结果如下:
PageInfo{pageNum=10, pageSize=2, size=2, startRow=19, endRow=20, total=99, pages=50, list=Page{count=true, pageNum=10, pageSize=2, startRow=18, endRow=20, total=99, pages=50, reasonable=false, pageSizeZero=false}[User [id=19, name=user19], User [id=20, name=user20]], prePage=9, nextPage=11, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=8, navigateFirstPage=6, navigateLastPage=13, navigatepageNums=[6, 7, 8, 9, 10, 11, 12, 13]}
说明:
PageHelper.startPage(10, 2);//分页插件应用Listlist = tService.selectPQ();//查询数据
PageInfopu=new PageInfo<>(list);//转为分页结果对象
PageInfo属性说明:
pageNum 当前页码pageSize 当前页码条数startRow 查询结果开始记录位置,即结果是第startRow条记录开始endRow 查询结果结束记录位置,即结果到第endRow条记录结束pages 所有记录总共分为pages页prePage 上一页页码nextPage 下一页页码isFirstPage 是否是第一页isLastPage 是否是最后一页hasPreviousPage 是否有前一页hasNextPage 是否有后一页navigatePages 导航条显示页码数目navigatePages,即navigatepageNums的个数navigatepageNums 导航条显示具体页码的值navigateFirstPage 导航条开始页码navigateLastPage 导航条结束页码total 总数据条数list 查询结果
注意:
(1)根据官方建议,mybatis配置方式和spring配置方式最好二选其一。
(2)编辑代码时要注意分页时机,如下给出一段官方的不安全代码:
PageHelper.startPage(1, 10);Listlist;if(param1 != null){ list = countryMapper.selectIf(param1);} else { list = new ArrayList ();}
根据官方说明,PageHelper使用静态的ThreadLocal参数(听说:ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量),分页参数和现场是绑定的。故上述代码中param1参数为null时,分页线程已经产生,但是没有被利用,也没有被释放(PageHelper在finally代码中自动清除了ThreadLocal存储对象),当这个线程再次被使用时就会导致分页结果与预期结果不一样的情况。而将上述代码改为如下代码就能保证安全:
Listlist;if(param1 != null){ PageHelper.startPage(1, 10); list = countryMapper.selectIf(param1);} else { list = new ArrayList ();}
当然也可以调用PageHelper.clearPage();方法来清除ThreadLocal,但官方认为没有必要,嗯,没必要。