数据分页(物理分页和逻辑分页)

# 数据分页

## 必须的的参数

#### 总数据条数(count)

+ 来源:从数据库中查询获得

#### 每页展示多少条数据(pageSize)

+ 来源:前端获取

#### 当前所在的页码(currentPage)

+ 来源:前端获取

#### 总页数(countPage)

+ 来源:计算得来

> 总页数 = 总数据条数 / 每页展示条数
>
> countPage = count / pageSize

#### 数据本身

+ 来源:数据库查询

## 物理分页

#### 什么是物理分页

? 所谓的物理分页其实就是直接通过数据库来实现返回一部分数据。每次只从数据库中查询一页的数据。与之相对应的还有逻辑分页。

#### Mysql中的实现语句

```sql
SELECT * FROM `shop` LIMIT (currentPage-1)*pageSize, pageSize;
```

#### Java程序

```java
private void doPhysicalPaganation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

// 获取页面传递过来的参数
String sCurrentPage = req.getParameter("currentPage");
String sPageSize= req.getParameter("pageSize");

// 当前页码默认展示第一页
int currentPage = 1;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
currentPage = Integer.parseInt(sCurrentPage);
} catch (NumberFormatException e) {
}

int pageSize = 10;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
pageSize = Integer.parseInt(sPageSize);
} catch (NumberFormatException e) {
}

Paganation<Student> paganation = new Paganation<>();
paganation.setCurrentPage(currentPage);
paganation.setPageSize(pageSize);

// 分页查询
studentDao.findByPageWithPhysical(paganation);

req.setAttribute("page", paganation);

req.getRequestDispatcher("physical.jsp").forward(req, resp);
}
```

```java
public Paganation<Student> findByPageWithPhysical(Paganation<Student> pageParam) {

Paganation<Student> page = pageParam;

Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 获取连接
conn = JDBCTools.getConnection();

// 获取当前页要展示的数据
// 创建预编译对象,预编译SQL语句
pstmt = conn.prepareStatement("select * from student limit ?,?");
// limit关键字第一个参数表示跳过结果集中的多少条数据
pstmt.setInt(1, (pageParam.getCurrentPage() - 1) * pageParam.getPageSize());
// limit关键字第二个参数表示从结果集中取多少条数据
pstmt.setInt(2, pageParam.getPageSize());

// 执行语句,获取结果集
rs = pstmt.executeQuery();

// 封装结果集
List<Student> datas = new ArrayList<Student>();
while(rs.next()) {
Student student = new Student();
student.setStuId(rs.getString("stu_id"));
student.setStuName(rs.getString("stu_name"));
student.setSex(rs.getString("sex"));
student.setAge(rs.getInt("age"));
student.setScience(rs.getString("science"));
student.setTelephone(rs.getString("telephone"));
datas.add(student);
}

// 将获取到的当前页要展示的数据封装到page对象中
page.setData(datas);

// 查询总数据条数
pstmt = conn.prepareStatement("select count(*) from student");
rs = pstmt.executeQuery();
int totalCount = 0;
if(rs.next()) {
totalCount = rs.getInt(1);
}

page.setTotalCount(totalCount);

} catch (SQLException e) {
e.printStackTrace();
}

return page;
}
```

## 逻辑分页

#### 什么是逻辑分页

? 所谓的逻辑分页其实就是通过内存来进行分页。具体来说,首次查询数据时,将所有数据都取出放到内存中,展示其他页的数据时,在内存中实现数据的截取,展示。

#### Mysql中的实现语句

```sql
SELECT * FROM `shop` ;
```

#### Java程序

```java
private void doLogicPaganation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


// 获取页面传递过来的参数
String sCurrentPage = req.getParameter("currentPage");
String sPageSize= req.getParameter("pageSize");

// 当前页码默认展示第一页
int currentPage = 1;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
currentPage = Integer.parseInt(sCurrentPage);
} catch (NumberFormatException e) {
}

int pageSize = 10;
try {
// 如果前端传递了具体的页码,我们就用前端传过来的
pageSize = Integer.parseInt(sPageSize);
} catch (NumberFormatException e) {
}

Paganation<Student> paganation = new Paganation<>();
paganation.setCurrentPage(currentPage);
paganation.setPageSize(pageSize);

// 分页查询
studentDao.findByPageWithLogic(paganation);

req.setAttribute("page", paganation);

req.getRequestDispatcher("logic.jsp").forward(req, resp);


}
```

```java
List<Student> cache = new ArrayList<>();
public Paganation<Student> findByPageWithLogic(Paganation<Student> pageParam) {
Paganation<Student> page = pageParam;

Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
List<Student> datas = null;
// 当缓存中有数据时,直接从缓存中取当前页数据,无需查数据库
if(cache.size() > 0) {
datas = getPageData(page);
} else {

// 如果缓存中没有数据,从数据库中查询所有数据,放入缓存中

// 获取连接
conn = JDBCTools.getConnection();
// 获取当前页要展示的数据
// 创建预编译对象,预编译SQL语句
pstmt = conn.prepareStatement("select * from student");

// 执行语句,获取结果集
rs = pstmt.executeQuery();

// 封装结果集
cache.clear();
while(rs.next()) {
Student student = new Student();
student.setStuId(rs.getString("stu_id"));
student.setStuName(rs.getString("stu_name"));
student.setSex(rs.getString("sex"));
student.setAge(rs.getInt("age"));
student.setScience(rs.getString("science"));
student.setTelephone(rs.getString("telephone"));
cache.add(student);
}

// 将获取到的当前页要展示的数据封装到page对象中
datas = getPageData(page);
}

page.setData(datas);
page.setTotalCount(cache.size());

} catch (SQLException e) {
e.printStackTrace();
}

return page;
}

/**
* 从缓存中获取当前页要展示的数据
* @param page
* @return
*/
private List<Student> getPageData(Paganation<Student> page) {
List<Student> datas = new ArrayList<>();
int startIdx = (page.getCurrentPage() - 1)*page.getPageSize();
int endIdx = page.getCurrentPage() * page.getPageSize();
if(endIdx > cache.size()) {
endIdx = cache.size();
}
datas = cache.subList(startIdx, endIdx);
return datas;
}
```

## 两种分页的优缺点

1. 逻辑分页效率高,占用内存空间,适合查询的数据少但是查询次数多的情况。
2. 物理分页效率低,节省内存空间,适合查询次数少但是查询数据较大的情况。

相关推荐