在电商业务中,支付接口系统需要保障交易数据准确、状态流转清晰,mysql作为成熟的关系型数据库,能够通过合理的表结构和事务机制支撑支付场景的核心需求。设计时需要先梳理支付流程的核心环节,再对应设计数据库表,最后实现接口逻辑。

核心表结构设计
支付接口系统需要存储订单、支付记录、支付回调三类核心数据,对应的mysql表设计如下:
1. 订单表 order_info
存储用户下单的基础信息,是支付流程的发起源头:
CREATE TABLE `order_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单ID', `order_no` varchar(64) NOT NULL COMMENT '订单编号,全局唯一', `user_id` bigint(20) NOT NULL COMMENT '用户ID', `total_amount` decimal(10,2) NOT NULL COMMENT '订单总金额', `order_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态 0待支付 1已支付 2已取消 3已退款', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单信息表';
2. 支付记录表 payment_record
存储每一笔支付请求的详细信息,关联对应的订单:
CREATE TABLE `payment_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '支付记录ID', `payment_no` varchar(64) NOT NULL COMMENT '支付流水号,全局唯一', `order_no` varchar(64) NOT NULL COMMENT '关联订单编号', `pay_amount` decimal(10,2) NOT NULL COMMENT '实际支付金额', `pay_channel` tinyint(4) NOT NULL COMMENT '支付渠道 1微信 2支付宝 3银行卡', `payment_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '支付状态 0待支付 1支付成功 2支付失败 3已关闭', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_payment_no` (`payment_no`), KEY `idx_order_no` (`order_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付记录表';
3. 支付回调表 payment_callback
存储第三方支付平台的回调信息,用于校验支付结果:
CREATE TABLE `payment_callback` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '回调记录ID', `payment_no` varchar(64) NOT NULL COMMENT '关联支付流水号', `callback_content` text NOT NULL COMMENT '回调原始内容', `callback_time` datetime NOT NULL COMMENT '回调时间', `handle_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '处理状态 0未处理 1已处理 2处理失败', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), KEY `idx_payment_no` (`payment_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付回调记录表';
核心接口实现逻辑
1. 发起支付接口
用户下单后调用该接口生成支付请求,需要开启mysql事务保障订单和支付记录的一致性:
<?php
// 发起支付接口逻辑示例
function createPayment($userId, $orderNo, $payChannel) {
$pdo = new PDO('mysql:host=127.0.0.1;dbname=payment_db;charset=utf8mb4', 'root', 'password');
$pdo->beginTransaction(); // 开启事务
try {
// 1. 校验订单状态
$stmt = $pdo->prepare('SELECT id, total_amount, order_status FROM order_info WHERE order_no = ? AND user_id = ?');
$stmt->execute([$orderNo, $userId]);
$order = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$order || $order['order_status'] != 0) {
throw new Exception('订单不存在或状态不可支付');
}
// 2. 生成支付流水号
$paymentNo = 'PAY' . date('YmdHis') . rand(1000, 9999);
$payAmount = $order['total_amount'];
// 3. 插入支付记录
$stmt = $pdo->prepare('INSERT INTO payment_record (payment_no, order_no, pay_amount, pay_channel, payment_status) VALUES (?, ?, ?, ?, 0)');
$stmt->execute([$paymentNo, $orderNo, $payAmount, $payChannel]);
// 4. 调用第三方支付接口获取支付参数(此处省略第三方调用逻辑)
$payParams = [
'payment_no' => $paymentNo,
'pay_amount' => $payAmount,
'channel' => $payChannel
];
$pdo->commit(); // 提交事务
return ['code' => 0, 'msg' => '支付请求创建成功', 'data' => $payParams];
} catch (Exception $e) {
$pdo->rollBack(); // 回滚事务
return ['code' => 1, 'msg' => $e->getMessage()];
}
}
?>
2. 支付回调处理接口
第三方支付平台异步通知支付结果时调用该接口,需要校验回调合法性并更新支付和订单状态:
<?php
// 支付回调处理接口示例
function handlePaymentCallback($callbackData) {
$pdo = new PDO('mysql:host=127.0.0.1;dbname=payment_db;charset=utf8mb4', 'root', 'password');
$pdo->beginTransaction();
try {
// 1. 校验回调签名(此处省略第三方签名校验逻辑)
$paymentNo = $callbackData['payment_no'];
$payStatus = $callbackData['pay_status']; // 假设第三方返回1为支付成功
// 2. 存储回调记录
$stmt = $pdo->prepare('INSERT INTO payment_callback (payment_no, callback_content, callback_time, handle_status) VALUES (?, ?, NOW(), 0)');
$stmt->execute([$paymentNo, json_encode($callbackData)]);
// 3. 查询支付记录
$stmt = $pdo->prepare('SELECT id, order_no, payment_status FROM payment_record WHERE payment_no = ?');
$stmt->execute([$paymentNo]);
$payment = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$payment || $payment['payment_status'] != 0) {
throw new Exception('支付记录不存在或状态异常');
}
// 4. 更新支付状态
$newPaymentStatus = $payStatus == 1 ? 1 : 2;
$stmt = $pdo->prepare('UPDATE payment_record SET payment_status = ? WHERE payment_no = ?');
$stmt->execute([$newPaymentStatus, $paymentNo]);
// 5. 如果支付成功,更新订单状态
if ($newPaymentStatus == 1) {
$stmt = $pdo->prepare('UPDATE order_info SET order_status = 1 WHERE order_no = ? AND order_status = 0');
$stmt->execute([$payment['order_no']]);
}
// 6. 更新回调处理状态
$stmt = $pdo->prepare('UPDATE payment_callback SET handle_status = 1 WHERE payment_no = ? ORDER BY id DESC LIMIT 1');
$stmt->execute([$paymentNo]);
$pdo->commit();
return ['code' => 0, 'msg' => '回调处理成功'];
} catch (Exception $e) {
$pdo->rollBack();
return ['code' => 1, 'msg' => $e->getMessage()];
}
}
?>
设计注意事项
- 所有涉及支付状态更新的操作必须开启mysql事务,避免数据不一致
- 订单编号、支付流水号需要全局唯一,建议通过雪花算法或者时间戳加随机数生成
- 支付回调接口需要做幂等处理,避免重复回调导致多次更新状态,可以通过支付流水号加状态校验实现
- 敏感金额字段使用decimal类型存储,避免使用float导致精度丢失
- 建议给常用的查询字段如order_no、payment_no添加索引,提升查询效率
支付接口系统涉及资金安全,实际生产环境中还需要增加风控校验、日志审计、异常重试等机制,本文仅展示基于mysql的基础设计思路。