php实现转账
PHP实现转账功能
实现转账功能需要处理数据库事务、金额校验、并发控制等关键点。以下是一个完整的PHP转账实现方案:
数据库表设计 创建用户账户表和交易记录表:

CREATE TABLE `accounts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`balance` decimal(15,2) NOT NULL DEFAULT '0.00',
`version` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `transactions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`from_user` int(11) NOT NULL,
`to_user` int(11) NOT NULL,
`amount` decimal(15,2) NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`status` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
PHP转账核心代码
function transferMoney($fromUserId, $toUserId, $amount) {
$db = new PDO('mysql:host=localhost;dbname=your_db', 'username', 'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$db->beginTransaction();
// 检查金额有效性
if ($amount <= 0) {
throw new Exception("转账金额必须大于零");
}
// 获取转出账户信息并加锁
$stmt = $db->prepare("SELECT balance FROM accounts WHERE user_id = ? FOR UPDATE");
$stmt->execute([$fromUserId]);
$fromAccount = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$fromAccount) {
throw new Exception("转出账户不存在");
}
// 检查余额是否充足
if ($fromAccount['balance'] < $amount) {
throw new Exception("账户余额不足");
}
// 获取转入账户信息并加锁
$stmt = $db->prepare("SELECT balance FROM accounts WHERE user_id = ? FOR UPDATE");
$stmt->execute([$toUserId]);
$toAccount = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$toAccount) {
throw new Exception("转入账户不存在");
}
// 执行转账操作
$stmt = $db->prepare("UPDATE accounts SET balance = balance - ? WHERE user_id = ?");
$stmt->execute([$amount, $fromUserId]);
$stmt = $db->prepare("UPDATE accounts SET balance = balance + ? WHERE user_id = ?");
$stmt->execute([$amount, $toUserId]);
// 记录交易
$stmt = $db->prepare("INSERT INTO transactions (from_user, to_user, amount, status) VALUES (?, ?, ?, 1)");
$stmt->execute([$fromUserId, $toUserId, $amount]);
$db->commit();
return true;
} catch (Exception $e) {
$db->rollBack();
error_log("转账失败: " . $e->getMessage());
return false;
}
}
并发控制优化 使用乐观锁防止并发问题:

// 在转账函数中添加版本检查
$stmt = $db->prepare("SELECT balance, version FROM accounts WHERE user_id = ?");
$stmt->execute([$fromUserId]);
$fromAccount = $stmt->fetch(PDO::FETCH_ASSOC);
// 更新时检查版本号
$stmt = $db->prepare("UPDATE accounts SET balance = balance - ?, version = version + 1 WHERE user_id = ? AND version = ?");
$affected = $stmt->execute([$amount, $fromUserId, $fromAccount['version']]);
if ($affected === 0) {
throw new Exception("账户信息已变更,请重试");
}
安全注意事项
- 使用预处理语句防止SQL注入
- 金额使用DECIMAL类型而非FLOAT避免精度问题
- 重要操作记录详细日志
- 考虑添加每日转账限额
- 对外暴露接口需要身份验证和防重放攻击机制
RESTful API实现示例
// transfer.php
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
$required = ['from_user', 'to_user', 'amount', 'token'];
foreach ($required as $field) {
if (empty($input[$field])) {
http_response_code(400);
echo json_encode(['error' => "缺少必要参数: $field"]);
exit;
}
}
// 验证token有效性
if (!verifyToken($input['token'])) {
http_response_code(401);
echo json_encode(['error' => '无效的认证令牌']);
exit;
}
$result = transferMoney($input['from_user'], $input['to_user'], $input['amount']);
if ($result) {
echo json_encode(['success' => true]);
} else {
http_response_code(500);
echo json_encode(['error' => '转账处理失败']);
}
以上实现包含了转账功能的核心要素,可根据实际业务需求进行调整和扩展。对于高并发场景,可能需要引入队列系统或分布式事务解决方案。






