本文目录导读:

我来介绍几种PHP实现账单查询的方法,从简单到复杂:
基础数据库查询实现
数据库表结构
CREATE TABLE bills (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
bill_no VARCHAR(50) UNIQUE NOT NULL,
amount DECIMAL(10,2) NOT NULL,
status TINYINT DEFAULT 0 COMMENT '0:待支付 1:已支付 2:已取消',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
pay_time TIMESTAMP NULL,
INDEX idx_user_id (user_id),
INDEX idx_bill_no (bill_no)
);
简单查询实现
<?php
class BillQuery {
private $db;
public function __construct($db) {
$this->db = $db;
}
// 按单号查询
public function findByBillNo($billNo) {
$sql = "SELECT * FROM bills WHERE bill_no = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$billNo]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
// 按用户和时间范围查询
public function findByUserAndDate($userId, $startDate, $endDate) {
$sql = "SELECT * FROM bills
WHERE user_id = ?
AND created_at BETWEEN ? AND ?
ORDER BY created_at DESC";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId, $startDate, $endDate]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
?>
带分页和筛选的高级查询
<?php
class BillQueryAdvanced {
private $db;
public function __construct($db) {
$this->db = $db;
}
/**
* 带筛选条件的查询
* @param array $filters 筛选条件
* @param int $page 当前页码
* @param int $pageSize 每页条数
* @return array 查询结果
*/
public function searchBills($filters = [], $page = 1, $pageSize = 20) {
$conditions = [];
$params = [];
// 构建查询条件
if (!empty($filters['user_id'])) {
$conditions[] = "user_id = ?";
$params[] = $filters['user_id'];
}
if (!empty($filters['bill_no'])) {
$conditions[] = "bill_no LIKE ?";
$params[] = "%{$filters['bill_no']}%";
}
if (!empty($filters['status'])) {
$conditions[] = "status = ?";
$params[] = $filters['status'];
}
if (!empty($filters['start_date'])) {
$conditions[] = "created_at >= ?";
$params[] = $filters['start_date'];
}
if (!empty($filters['end_date'])) {
$conditions[] = "created_at <= ?";
$params[] = $filters['end_date'];
}
// 金额范围
if (!empty($filters['min_amount'])) {
$conditions[] = "amount >= ?";
$params[] = $filters['min_amount'];
}
if (!empty($filters['max_amount'])) {
$conditions[] = "amount <= ?";
$params[] = $filters['max_amount'];
}
// 构建WHERE子句
$where = count($conditions) > 0 ? "WHERE " . implode(" AND ", $conditions) : "";
// 计算总数
$countSql = "SELECT COUNT(*) FROM bills {$where}";
$stmt = $this->db->prepare($countSql);
$stmt->execute($params);
$total = $stmt->fetchColumn();
// 分页查询
$offset = ($page - 1) * $pageSize;
$sql = "SELECT * FROM bills {$where} ORDER BY created_at DESC LIMIT ? OFFSET ?";
$params[] = $pageSize;
$params[] = $offset;
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
$bills = $stmt->fetchAll(PDO::FETCH_ASSOC);
return [
'data' => $bills,
'total' => $total,
'page' => $page,
'pageSize' => $pageSize,
'totalPages' => ceil($total / $pageSize)
];
}
}
?>
缓存优化查询
<?php
class CachedBillQuery {
private $db;
private $redis;
private $cacheTime = 300; // 5分钟缓存
public function findWithCache($billNo) {
$cacheKey = "bill:{$billNo}";
// 尝试从缓存获取
$cachedData = $this->redis->get($cacheKey);
if ($cachedData !== false) {
return json_decode($cachedData, true);
}
// 从数据库查询
$sql = "SELECT * FROM bills WHERE bill_no = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$billNo]);
$bill = $stmt->fetch(PDO::FETCH_ASSOC);
if ($bill) {
// 写入缓存
$this->redis->setex($cacheKey, $this->cacheTime, json_encode($bill));
}
return $bill;
}
// 批量查询优化
public function findBatch(array $billNos) {
$results = [];
$missedBills = [];
// 先从缓存查找
foreach ($billNos as $billNo) {
$cacheKey = "bill:{$billNo}";
$cachedData = $this->redis->get($cacheKey);
if ($cachedData !== false) {
$results[$billNo] = json_decode($cachedData, true);
} else {
$missedBills[] = $billNo;
}
}
// 查询未缓存的数据
if (!empty($missedBills)) {
$placeholders = implode(',', array_fill(0, count($missedBills), '?'));
$sql = "SELECT * FROM bills WHERE bill_no IN ($placeholders)";
$stmt = $this->db->prepare($sql);
$stmt->execute($missedBills);
$bills = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($bills as $bill) {
$results[$bill['bill_no']] = $bill;
// 写入缓存
$cacheKey = "bill:{$bill['bill_no']}";
$this->redis->setex($cacheKey, $this->cacheTime, json_encode($bill));
}
}
return $results;
}
}
?>
RESTful API接口实现
<?php
// bill_api.php - 账单查询API
header('Content-Type: application/json');
require_once 'BillQueryAdvanced.php';
require_once 'CachedBillQuery.php';
class BillAPI {
private $queryService;
public function __construct() {
$this->queryService = new BillQueryAdvanced($this->getDB());
}
public function handleRequest() {
$method = $_SERVER['REQUEST_METHOD'];
switch ($method) {
case 'GET':
$this->handleGet();
break;
default:
$this->respond(405, ['error' => 'Method not allowed']);
}
}
private function handleGet() {
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$pathParts = explode('/', trim($path, '/'));
// 获取单个账单
if (count($pathParts) >= 3 && $pathParts[2] === 'bills' && isset($pathParts[3])) {
$billNo = $pathParts[3];
$bill = $this->queryService->findWithCache($billNo);
if ($bill) {
$this->respond(200, $bill);
} else {
$this->respond(404, ['error' => 'Bill not found']);
}
}
// 搜索账单
else if (count($pathParts) >= 2 && $pathParts[1] === 'bills') {
$filters = $_GET;
$page = isset($filters['page']) ? (int)$filters['page'] : 1;
$pageSize = isset($filters['pageSize']) ? (int)$filters['pageSize'] : 20;
// 移除分页参数
unset($filters['page'], $filters['pageSize']);
$result = $this->queryService->searchBills($filters, $page, $pageSize);
$this->respond(200, $result);
} else {
$this->respond(404, ['error' => 'Not found']);
}
}
private function respond($statusCode, $data) {
http_response_code($statusCode);
echo json_encode($data, JSON_UNESCAPED_UNICODE);
}
private function getDB() {
// 数据库连接配置
$dsn = "mysql:host=localhost;dbname=test;charset=utf8mb4";
return new PDO($dsn, 'root', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
}
}
// 路由处理
$api = new BillAPI();
$api->handleRequest();
?>
前端查询示例
// 前端JavaScript查询
class BillQuery {
async searchBills(filters) {
const params = new URLSearchParams(filters);
const response = await fetch(`/api/bills?${params}`);
if (!response.ok) {
throw new Error('查询失败');
}
return await response.json();
}
async queryByBillNo(billNo) {
const response = await fetch(`/api/bills/${billNo}`);
if (!response.ok) {
throw new Error('账单未找到');
}
return await response.json();
}
}
// 使用示例
const query = new BillQuery();
// 按条件查询
const result = await query.searchBills({
user_id: 123,
start_date: '2024-01-01',
end_date: '2024-12-31',
status: 1,
page: 1,
pageSize: 20
});
// 按单号查询
const bill = await query.queryByBillNo('BILL20240101001');
性能优化建议
<?php
// 1. 使用索引
// 在数据库中添加复合索引
$sql = "CREATE INDEX idx_user_date ON bills(user_id, created_at)";
// 2. 使用连接池
$pool = new PdoPool();
$connection = $pool->getConnection();
// 3. 异步查询(使用Swoole)
swoole_async::exec("mysql -e 'SELECT * FROM bills WHERE ...'", function($result) {
// 处理结果
});
// 4. 查询结果序列化
class BillSerializer {
public static function serialize($bill) {
return [
'id' => (int)$bill['id'],
'billNo' => $bill['bill_no'],
'amount' => (float)$bill['amount'],
'statusText' => self::getStatusText($bill['status']),
'createdAt' => date('Y-m-d H:i:s', strtotime($bill['created_at']))
];
}
private static function getStatusText($status) {
$map = [0 => '待支付', 1 => '已支付', 2 => '已取消'];
return $map[$status] ?? '未知';
}
}
?>
安全注意事项
- SQL注入防护:始终使用预处理语句
- 权限控制:验证用户是否有权查询
- 数据脱敏:敏感信息加密或脱敏
- 限流控制:防止频繁查询
- 日志记录:记录所有查询操作
这就是PHP实现账单查询的完整方案,可以根据实际需求选择合适的方式实现。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播