修复数据库分离: pay_orders→orders.db + web_transactions→web.db,双库不再混用

This commit is contained in:
ypsdf1
2026-07-16 14:03:50 +08:00
parent 61bc4672a9
commit 95630c7609
3 changed files with 80 additions and 66 deletions
+20 -17
View File
@@ -270,7 +270,7 @@ function createOrder($token) {
}
$player = $info['player'];
$db = getDB();
$db = getOrdersDB();
ensurePayOrdersTable($db);
// ★ 防重复支付:检查玩家是否有未支付的已有订单(仅5分钟内有效)
@@ -391,9 +391,10 @@ function handleNotify() {
exit;
}
$db = getDB();
$db = getOrdersDB(); // orders.db — pay_orders
ensurePayOrdersTable($db);
ensureWebTransactionsTable($db);
$webDb = getDB(); // web.db — web_transactions
ensureWebTransactionsTable($webDb);
$stmt = $db->prepare("SELECT * FROM pay_orders WHERE out_trade_no = :no");
$stmt->bindValue(':no', $outTradeNo, SQLITE3_TEXT);
@@ -416,8 +417,8 @@ function handleNotify() {
$ins->bindValue(':t', $now, SQLITE3_INTEGER);
$ins->execute();
// 写 web_transactions
$txIns = $db->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(callback同步)', '在线充值(支付宝)', :d, 'pending', :t)");
// 写 web_transactions → web.db
$txIns = $webDb->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(callback同步)', '在线充值(支付宝)', :d, 'pending', :t)");
$txIns->bindValue(':p', $platformPlayer, SQLITE3_TEXT);
$txIns->bindValue(':a', $bonds, SQLITE3_INTEGER);
$txIns->bindValue(':d', $outTradeNo, SQLITE3_TEXT);
@@ -451,15 +452,15 @@ function handleNotify() {
exit;
}
// 5) 标记订单已支付
// 5) 标记订单已支付(orders.db)
$stmt = $db->prepare("UPDATE pay_orders SET status='paid', trade_no=:tn, paid_at=:t WHERE out_trade_no=:no");
$stmt->bindValue(':tn', $params['trade_no'] ?? '', SQLITE3_TEXT);
$stmt->bindValue(':t', time(), SQLITE3_INTEGER);
$stmt->bindValue(':no', $outTradeNo, SQLITE3_TEXT);
$stmt->execute();
// 6) 写 web_transactions(recharge) 供 Java 高频定时器拉取 → addBonds 到账
$stmt = $db->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台', '在线充值(支付宝)', :d, 'pending', :t)");
// 6) 写 web_transactions(recharge) 供 Java 高频定时器拉取 → addBonds 到账 → web.db
$stmt = $webDb->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台', '在线充值(支付宝)', :d, 'pending', :t)");
$stmt->bindValue(':p', $row['player_name'], SQLITE3_TEXT);
$stmt->bindValue(':a', (int)$row['bond_amount'], SQLITE3_INTEGER);
$stmt->bindValue(':d', $outTradeNo, SQLITE3_TEXT);
@@ -483,7 +484,7 @@ function handlePayRedirect() {
echo '缺少订单号';
exit;
}
$db = getDB();
$db = getOrdersDB();
ensurePayOrdersTable($db);
$stmt = $db->prepare("SELECT submit_params, status, player_name FROM pay_orders WHERE out_trade_no = :no");
$stmt->bindValue(':no', $outTradeNo, SQLITE3_TEXT);
@@ -555,7 +556,7 @@ function queryOrder($token) {
if (!$outTradeNo) {
error('缺少订单号');
}
$db = getDB();
$db = getOrdersDB();
ensurePayOrdersTable($db);
$stmt = $db->prepare("SELECT * FROM pay_orders WHERE out_trade_no=:no AND player_name=:p");
$stmt->bindValue(':no', $outTradeNo, SQLITE3_TEXT);
@@ -607,12 +608,13 @@ function queryOrder($token) {
$ins->bindValue(':t', $now, SQLITE3_INTEGER);
$ins->execute();
// 写 web_transactions
$txCheck = $db->prepare("SELECT id FROM web_transactions WHERE detail = :d AND type = 'recharge' LIMIT 1");
// 写 web_transactions → web.db
$webDb = getDB();
$txCheck = $webDb->prepare("SELECT id FROM web_transactions WHERE detail = :d AND type = 'recharge' LIMIT 1");
$txCheck->bindValue(':d', $outTradeNo, SQLITE3_TEXT);
$txRow = $txCheck->execute()->fetchArray(SQLITE3_ASSOC);
if (!$txRow) {
$txIns = $db->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(查询同步)', '在线充值(支付宝)', :d, 'pending', :t)");
$txIns = $webDb->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(查询同步)', '在线充值(支付宝)', :d, 'pending', :t)");
$txIns->bindValue(':p', $platformPlayer, SQLITE3_TEXT);
$txIns->bindValue(':a', $bonds, SQLITE3_INTEGER);
$txIns->bindValue(':d', $outTradeNo, SQLITE3_TEXT);
@@ -662,12 +664,13 @@ function queryOrder($token) {
$upd->bindValue(':no', $outTradeNo, SQLITE3_TEXT);
$upd->execute();
// 写 web_transactions(幂等)
$txCheck = $db->prepare("SELECT id FROM web_transactions WHERE detail = :d AND type = 'recharge' LIMIT 1");
// 写 web_transactions(幂等)→ web.db
$webDb = getDB();
$txCheck = $webDb->prepare("SELECT id FROM web_transactions WHERE detail = :d AND type = 'recharge' LIMIT 1");
$txCheck->bindValue(':d', $outTradeNo, SQLITE3_TEXT);
$txRow = $txCheck->execute()->fetchArray(SQLITE3_ASSOC);
if (!$txRow) {
$txIns = $db->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(直查)', '在线充值(支付宝)', :d, 'pending', :t)");
$txIns = $webDb->prepare("INSERT INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(直查)', '在线充值(支付宝)', :d, 'pending', :t)");
$txIns->bindValue(':p', $info['player'], SQLITE3_TEXT);
$txIns->bindValue(':a', (int)$row['bond_amount'], SQLITE3_INTEGER);
$txIns->bindValue(':d', $outTradeNo, SQLITE3_TEXT);
@@ -839,7 +842,7 @@ function findRecentOrder($token) {
if (!$info || empty($info['player'])) {
error('登录状态无效', 401);
}
$db = getDB();
$db = getOrdersDB();
ensurePayOrdersTable($db);
// 查最近5分钟内的订单(优先created,再paid)
$fiveMinAgo = time() - 300;
+35 -20
View File
@@ -32,8 +32,9 @@ $PLATFORM_DB_USER = defined('PAY_MYSQL_USER') ? PAY_MYSQL_USER : 'kH3C3LLinNwYdT
$PLATFORM_DB_PASS = defined('PAY_MYSQL_PASS') ? PAY_MYSQL_PASS : 'sRhsdxrpHBhmSsp8';
$GLOBALS['PLATFORM_DB_PREFIX'] = 'pay_'; $PLATFORM_DB_PREFIX = 'pay_';
// SQLite 数据库路径(与 core.php 一致:/caoyuan.ypshidifu.cn/plugin/db/web.db)
$SQLITE_DB_PATH = __DIR__ . '/../db/web.db';
// SQLite 数据库路径
$GLOBALS['SQLITE_DB_PATH'] = __DIR__ . '/../db/web.db'; // web_transactions (Java读写)
$GLOBALS['ORDERS_DB_PATH'] = __DIR__ . '/../db/orders.db'; // pay_orders (PHP读写)
if (!function_exists('debugLog')) {
function debugLog($msg, $ctx = []) {
@@ -47,13 +48,39 @@ function debugLog($msg, $ctx = []) {
} // end if (!function_exists('debugLog'))
function getSQLite() {
// web.db — Java 高频读写(web_transactions 表)
static $db = null;
if ($db === null) {
$db = new SQLite3($GLOBALS['SQLITE_DB_PATH']);
$db->enableExceptions(true);
$db->exec('PRAGMA journal_mode=WAL');
$db->exec('PRAGMA busy_timeout=5000');
// 确保表存在(幂等兜底)
// web_transactions 表(Java 读取补单)
$db->exec("CREATE TABLE IF NOT EXISTS web_transactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_name TEXT,
type TEXT,
amount INTEGER,
operator TEXT,
reason TEXT,
detail TEXT,
status TEXT DEFAULT 'pending',
created_at INTEGER
)");
@$db->exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_web_tx_detail_type ON web_transactions(detail, type)");
}
return $db;
}
function getOrdersSQLite() {
// orders.db — PHP 订单库(pay_orders 表),独立于 Java 的 web.db
static $db = null;
if ($db === null) {
$db = new SQLite3($GLOBALS['ORDERS_DB_PATH']);
$db->enableExceptions(true);
$db->exec('PRAGMA journal_mode=WAL');
$db->exec('PRAGMA busy_timeout=5000');
// pay_orders 表
$db->exec("CREATE TABLE IF NOT EXISTS pay_orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
out_trade_no TEXT UNIQUE,
@@ -69,19 +96,6 @@ function getSQLite() {
created_at INTEGER,
paid_at INTEGER
)");
$db->exec("CREATE TABLE IF NOT EXISTS web_transactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_name TEXT,
type TEXT,
amount INTEGER,
operator TEXT,
reason TEXT,
detail TEXT,
status TEXT DEFAULT 'pending',
created_at INTEGER
)");
// 唯一约束:同 detail+type 不允许重复(防 race condition/重复补单)
@$db->exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_web_tx_detail_type ON web_transactions(detail, type)");
}
return $db;
}
@@ -160,7 +174,8 @@ function pollPaidOrders() {
return;
}
$sqlite = getSQLite();
$sqlite = getOrdersSQLite(); // orders.db(pay_orders)
$webSqlite = getSQLite(); // web.db(web_transactions)
try {
$pdo = getPlatformDB();
@@ -267,8 +282,8 @@ function pollPaidOrders() {
$upd->execute();
}
// 写 web_transactions(幂等:INSERT OR IGNORE 防止竞态条件重复插入)
$txIns = $sqlite->prepare("INSERT OR IGNORE INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(补单)', '在线充值(支付宝)', :d, 'pending', :t)");
// 写 web_transactions(幂等:INSERT OR IGNORE 防止竞态条件重复插入)→ web.db
$txIns = $webSqlite->prepare("INSERT OR IGNORE INTO web_transactions (player_name, type, amount, operator, reason, detail, status, created_at) VALUES (:p, 'recharge', :a, '支付平台(补单)', '在线充值(支付宝)', :d, 'pending', :t)");
$txIns->bindValue(':p', $playerName, SQLITE3_TEXT);
$txIns->bindValue(':a', $bonds, SQLITE3_INTEGER);
$txIns->bindValue(':d', $outTradeNo, SQLITE3_TEXT);
@@ -276,7 +291,7 @@ function pollPaidOrders() {
$txIns->execute();
// 检查是否是新插入的(affected_rows > 0 表示新插入,=0 表示已存在被忽略)
if ($sqlite->changes() > 0) {
if ($webSqlite->changes() > 0) {
debugLog('[poller_online] 充值交易已写入 web_transactions', [
'player' => $playerName, 'bonds' => $bonds,
'out_trade_no' => $outTradeNo, 'money' => $money,
+25 -29
View File
@@ -66,36 +66,32 @@ function handleOrderList() {
$db = getOrdersDB();
ensurePayOrdersTable($db);
// ★ 自动迁移:如果 orders.db 为空但 web.db 有 pay_orders 数据,从 web.db 迁移过来
// ★ 增量迁移:从 web.db 同步缺失的 pay_orders 到 orders.db(处理历史数据)
try {
$countStmt = $db->query("SELECT COUNT(*) as cnt FROM pay_orders");
$cnt = $countStmt->fetchArray(SQLITE3_ASSOC)['cnt'] ?? 0;
if ($cnt == 0) {
$webDb = getDB();
// 检查 web.db 是否有 pay_orders 表
$tableCheck = $webDb->query("SELECT name FROM sqlite_master WHERE type='table' AND name='pay_orders'");
if ($tableCheck->fetchArray()) {
// 迁移数据
$migrateData = $webDb->query("SELECT * FROM pay_orders");
$ins = $db->prepare("INSERT OR IGNORE INTO pay_orders (out_trade_no, trade_no, player_name, tier_id, money, bond_amount, status, name, platform_sign, submit_params, created_at, paid_at) VALUES (:no, :tn, :p, :ti, :m, :b, :s, :n, :ps, :sp, :ca, :pa)");
$migrated = 0;
while ($row = $migrateData->fetchArray(SQLITE3_ASSOC)) {
$ins->bindValue(':no', $row['out_trade_no'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':tn', $row['trade_no'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':p', $row['player_name'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':ti', $row['tier_id'] ?? 0, SQLITE3_INTEGER);
$ins->bindValue(':m', $row['money'] ?? '0', SQLITE3_TEXT);
$ins->bindValue(':b', $row['bond_amount'] ?? 0, SQLITE3_INTEGER);
$ins->bindValue(':s', $row['status'] ?? 'created', SQLITE3_TEXT);
$ins->bindValue(':n', $row['name'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':ps', $row['platform_sign'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':sp', $row['submit_params'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':ca', $row['created_at'] ?? 0, SQLITE3_INTEGER);
$ins->bindValue(':pa', $row['paid_at'] ?? 0, SQLITE3_INTEGER);
$ins->execute();
$migrated++;
}
debugLog('[handleOrderList] 自动迁移web.db→orders.db', ['migrated' => $migrated]);
$webDb = getDB();
$tableCheck = $webDb->query("SELECT name FROM sqlite_master WHERE type='table' AND name='pay_orders'");
if ($tableCheck->fetchArray()) {
$migrateData = $webDb->query("SELECT * FROM pay_orders");
$ins = $db->prepare("INSERT OR IGNORE INTO pay_orders (out_trade_no, trade_no, player_name, tier_id, money, bond_amount, status, name, platform_sign, submit_params, created_at, paid_at) VALUES (:no, :tn, :p, :ti, :m, :b, :s, :n, :ps, :sp, :ca, :pa)");
$migrated = 0;
while ($row = $migrateData->fetchArray(SQLITE3_ASSOC)) {
$ins->bindValue(':no', $row['out_trade_no'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':tn', $row['trade_no'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':p', $row['player_name'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':ti', $row['tier_id'] ?? 0, SQLITE3_INTEGER);
$ins->bindValue(':m', $row['money'] ?? '0', SQLITE3_TEXT);
$ins->bindValue(':b', $row['bond_amount'] ?? 0, SQLITE3_INTEGER);
$ins->bindValue(':s', $row['status'] ?? 'created', SQLITE3_TEXT);
$ins->bindValue(':n', $row['name'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':ps', $row['platform_sign'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':sp', $row['submit_params'] ?? '', SQLITE3_TEXT);
$ins->bindValue(':ca', $row['created_at'] ?? 0, SQLITE3_INTEGER);
$ins->bindValue(':pa', $row['paid_at'] ?? 0, SQLITE3_INTEGER);
$ins->execute();
if ($db->changes() > 0) $migrated++;
}
if ($migrated > 0) {
debugLog('[handleOrderList] 增量迁移web.db→orders.db', ['migrated' => $migrated]);
}
}
} catch (Exception $e) {