本文目录导读:

- 分页查询核心概念
- SQL 分页查询示例
- Node.js + MySQL 实现
- Python + SQLAlchemy 实现
- Java Spring Boot 实现
- 前端分页组件示例 (React)
- 高级分页技巧
- 最佳实践建议
我来详细介绍如何编写数据分页查询脚本,包含不同数据库和后端语言的实现方式。
分页查询核心概念
分页查询通常需要两个参数:
- page (当前页码)
- pageSize (每页记录数)
计算关键值:
- offset = (page - 1) × pageSize
- limit = pageSize
SQL 分页查询示例
MySQL / PostgreSQL
-- 基础分页查询
SELECT * FROM users
ORDER BY id
LIMIT ? OFFSET ?;
-- 获取总记录数
SELECT COUNT(*) as total FROM users;
-- 完整分页查询
SELECT
u.*,
(SELECT COUNT(*) FROM users) as total_count
FROM users u
ORDER BY u.id
LIMIT ? OFFSET ?;
SQL Server
-- SQL Server 2012+
SELECT * FROM users
ORDER BY id
OFFSET ? ROWS
FETCH NEXT ? ROWS ONLY;
-- 旧版本使用 ROW_NUMBER
WITH UserCTE AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY id) as RowNum
FROM users
)
SELECT * FROM UserCTE
WHERE RowNum BETWEEN ? AND ?;
Oracle
SELECT * FROM (
SELECT a.*, ROWNUM rn
FROM (
SELECT * FROM users ORDER BY id
) a
WHERE ROWNUM <= ?
)
WHERE rn > ?;
Node.js + MySQL 实现
// pagination.js
const mysql = require('mysql2/promise');
class PaginationService {
constructor(pool) {
this.pool = pool;
}
async getPaginatedData(table, page = 1, pageSize = 10, conditions = {}) {
const offset = (page - 1) * pageSize;
// 构建查询条件
let whereClause = '';
let params = [];
if (Object.keys(conditions).length > 0) {
whereClause = 'WHERE ' + Object.keys(conditions)
.map(key => `${key} = ?`)
.join(' AND ');
params = Object.values(conditions);
}
try {
// 获取总记录数
const [countResult] = await this.pool.execute(
`SELECT COUNT(*) as total FROM ${table} ${whereClause}`,
params
);
const total = countResult[0].total;
// 获取分页数据
const [rows] = await this.pool.execute(
`SELECT * FROM ${table} ${whereClause} ORDER BY id LIMIT ? OFFSET ?`,
[...params, pageSize, offset]
);
return {
data: rows,
pagination: {
page,
pageSize,
total,
totalPages: Math.ceil(total / pageSize),
hasNext: page < Math.ceil(total / pageSize),
hasPrev: page > 1
}
};
} catch (error) {
throw new Error(`Pagination failed: ${error.message}`);
}
}
}
// 使用示例
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb'
});
const paginationService = new PaginationService(pool);
app.get('/api/users', async (req, res) => {
try {
const { page = 1, pageSize = 10 } = req.query;
const result = await paginationService.getPaginatedData(
'users',
parseInt(page),
parseInt(pageSize)
);
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
Python + SQLAlchemy 实现
# pagination.py
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from dataclasses import dataclass
from typing import Optional, List, Any
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
db = SQLAlchemy(app)
@dataclass
class PaginationResult:
data: List[Any]
pagination: dict
class PaginationMixin:
@classmethod
def paginate(cls, page: int = 1, page_size: int = 10,
filters: Optional[dict] = None, order_by: str = 'id'):
"""通用分页方法"""
query = cls.query
# 应用过滤条件
if filters:
for key, value in filters.items():
query = query.filter(getattr(cls, key) == value)
# 计算总记录数
total = query.count()
# 获取分页数据
offset = (page - 1) * page_size
data = query.order_by(order_by).offset(offset).limit(page_size).all()
return PaginationResult(
data=data,
pagination={
'page': page,
'page_size': page_size,
'total': total,
'total_pages': (total + page_size - 1) // page_size,
'has_next': page < (total + page_size - 1) // page_size,
'has_prev': page > 1
}
)
# 模型类
class User(db.Model, PaginationMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
email = db.Column(db.String(100))
class Product(db.Model, PaginationMixin):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))
price = db.Column(db.Float)
# API 路由
@app.route('/api/items/<model_name>')
def get_paginated_items(model_name):
try:
page = request.args.get('page', 1, type=int)
page_size = request.args.get('page_size', 10, type=int)
# 模型映射
models = {
'users': User,
'products': Product
}
if model_name not in models:
return jsonify({'error': 'Invalid model'}), 400
model = models[model_name]
# 构建过滤条件
filters = {}
if 'status' in request.args:
filters['status'] = request.args['status']
result = model.paginate(page, page_size, filters)
# 序列化结果
serialized_data = []
for item in result.data:
item_dict = {col.name: getattr(item, col.name)
for col in item.__table__.columns}
serialized_data.append(item_dict)
return jsonify({
'data': serialized_data,
'pagination': result.pagination
})
except Exception as e:
return jsonify({'error': str(e)}), 500
Java Spring Boot 实现
// PaginationService.java
@Service
public class PaginationService {
@Autowired
private JdbcTemplate jdbcTemplate;
public PaginatedResult executePaginationQuery(
String baseQuery,
String countQuery,
Object[] params,
int page,
int pageSize,
RowMapper<?> rowMapper) {
int offset = (page - 1) * pageSize;
// 获取总记录数
int total = jdbcTemplate.queryForObject(countQuery, params, Integer.class);
// 获取分页数据
String paginatedQuery = baseQuery + " LIMIT ? OFFSET ?";
Object[] paginatedParams = ArrayUtils.addAll(params, pageSize, offset);
List<?> data = jdbcTemplate.query(paginatedQuery, paginatedParams, rowMapper);
return new PaginatedResult(data, page, pageSize, total);
}
}
// 更专业的 PageHelper 使用方式
@Service
public class UserService {
public PageInfo<User> getUsers(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<User> users = userMapper.selectAll();
return new PageInfo<>(users);
}
}
前端分页组件示例 (React)
// Pagination.jsx
import React, { useState, useEffect } from 'react';
const PaginatedList = () => {
const [data, setData] = useState([]);
const [pagination, setPagination] = useState({
page: 1,
pageSize: 10,
total: 0,
totalPages: 0
});
const [loading, setLoading] = useState(false);
const fetchData = async (page = 1) => {
setLoading(true);
try {
const response = await fetch(
`/api/items/users?page=${page}&page_size=10`
);
const result = await response.json();
setData(result.data);
setPagination(result.pagination);
} catch (error) {
console.error('Fetch error:', error);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, []);
const handlePageChange = (newPage) => {
if (newPage >= 1 && newPage <= pagination.totalPages) {
fetchData(newPage);
}
};
return (
<div>
{loading ? (
<div>Loading...</div>
) : (
<>
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
<PaginationControls
currentPage={pagination.page}
totalPages={pagination.totalPages}
onPageChange={handlePageChange}
/>
</>
)}
</div>
);
};
// 分页控件组件
const PaginationControls = ({ currentPage, totalPages, onPageChange }) => {
const pages = [];
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
return (
<div className="pagination">
<button
onClick={() => onPageChange(currentPage - 1)}
disabled={currentPage <= 1}
>
上一页
</button>
{pages.map(page => (
<button
key={page}
onClick={() => onPageChange(page)}
className={page === currentPage ? 'active' : ''}
>
{page}
</button>
))}
<button
onClick={() => onPageChange(currentPage + 1)}
disabled={currentPage >= totalPages}
>
下一页
</button>
</div>
);
};
高级分页技巧
游标分页(Cursor-based pagination)
-- 适用于大数据集,避免OFFSET性能问题 SELECT * FROM users WHERE id > ? ORDER BY id LIMIT ?; -- 结合时间戳 SELECT * FROM posts WHERE created_at < ? ORDER BY created_at DESC LIMIT ?;
缓存优化
# 使用Redis缓存分页结果
import redis
import json
class CachedPagination:
def __init__(self, redis_client):
self.redis = redis_client
def get_paginated_data(self, cache_key, page, page_size, query_func):
cache_key = f"{cache_key}:page:{page}:size:{page_size}"
# 尝试从缓存获取
cached = self.redis.get(cache_key)
if cached:
return json.loads(cached)
# 执行查询
result = query_func(page, page_size)
# 缓存结果(设置过期时间)
self.redis.setex(cache_key, 300, json.dumps(result))
return result
最佳实践建议
- 索引优化:确保排序和WHERE条件字段有索引
- 限制最大页数:防止恶意请求
- 使用光标分页:处理大数据集
- 缓存热门页:提升性能
- 参数验证:防止SQL注入
- 统一响应格式:便于前端处理
这个框架可以根据你的具体需求进行调整和扩展,需要我详细解释某个特定部分吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播