php购票排位_用PHP+MySQL实现12306购票和退票以及余票查询逻辑
普通商品的庫存之間沒有關聯性,庫存量都是確定的. 火車票跟普通商品不同,同一車次不同路段的車票的庫存可能會相互影響. 所以數據庫中不應存儲某個車次某個路段的余票數量,而應存儲該車次該路段已售的車票數量. 也就是普通商品存的是剩下的,而火車票存的是已售的.
車票表:
(車次, 路段(區間), 已售, 限售, 已售座位, 出發日)
(1024, [1,2], 0)
(1024, [1,2,3], 0)
(1024, [1,2,3,4], 0)
(1024, [2,3], 0)
(1024, [2,3,4], 0)
(1024, [3,4], 0)
主鍵是自增字段,"車次"+"路段"這2個字段組成聯合索引,添加唯一約束.
優化并發時,可以考慮根據"出發日"或"車次"進行分表分庫.
路段[1,2,3]的含義是:從車站1上車,經過車站2(停站),到車站3下車,編號有序.
如果要給不同的路段配置不同的出票限額,可以添加一個"限售"字段.
購票邏輯:
例如用戶購買路段[2,3,4]的車票時,
程序找出跟目標路段[2,3,4]有交集(相交元素>=2)的路段,算法如下:
function section(array $arr, array &$sub) {
$size = count($arr);
if ($size == 1) return;
for ($i = 2; $i <= $size; $i++) {
// 從位置0開始,取$i個元素,不影響輸入的數組.
$sub[] = array_slice($arr, 0, $i);
}
array_shift($arr); // 刪除數組開頭元素
section($arr, $sub); // 遞歸
}
$all = array(1,2,3,4);
$sub = array();
section($all, $sub); // 找到該車次包含的所有路段
$target = array(2,3,4); // 目標路段
$related = array(); // 目標路段的相關路段(相交路段)
foreach ($sub as $v) {
$intersect = array_intersect($target, $v);
if (count($intersect) >= 2) {
$related[] = $v;
}
}
var_export($related);
// 得到
[1,2,3]
[1,2,3,4]
[2,3]
[2,3,4]
[3,4]
如果相關路段的票合計小于500(這里假設列車滿載為500人),
則用戶能夠購票,即[2,3,4]這個路段已售的票數+1.
SQL購票邏輯如下(以MySQL為例):
SET AUTOCOMMIT=0;
START TRANSACTION; 或 BEGIN; --開啟事務
SELECT 已售 FROM 車票表 WHERE 車次=1024
AND 路段 IN ('1,2,3', '1,2,3,4', '2,3', '2,3,4', '3,4') FOR UPDATE;
UPDATE 車票表 SET 已售=(已售+1) WHERE 車次=1024 AND 路段='2,3,4';
COMMIT; --提交事務
SET AUTOCOMMIT=1;
其中 select for update 的作用是讀上鎖(對讀出的行上寫鎖),依賴事務.
select 區間 from 車票表 where 車次=1024 and 區間 like '%2,3,4%';
在本例中得到:
[1,2,3,4]
function foo(array $arr, array &$tmp) {
$size = count($arr);
if($size == 1) return;
for($i=2;$i<=$size;$i++) {
$tmp[] = array_slice($arr, 0, $i);
}
array_shift($arr);
foo($arr, $tmp);
}
$arr = array(2,3,4);
$tmp = array();
foo($arr, $tmp);
var_export($tmp);
在本例中得到:
[2,3]
[2,3,4]
[3,4]
退票邏輯比購票邏輯簡單得多,直接給對應車次,對應區間的已售車票-1即可:
UPDATE 車票表 SET 已售=(已售-1) WHERE 車次=1024 AND 路段='2,3,4';
余票查詢邏輯:
例如查詢車次1024上區間[2,3,4]的余票:
SELECT 已售 FROM 車票表 WHERE 車次=1024
AND 路段 IN ('1,2,3', '1,2,3,4', '2,3', '2,3,4', '3,4');
用500減去上述區間已售車票的和就是區間[2,3,4]上的余票.
這里假設列車滿載為500人.
座位分配邏輯:
一列火車,其座位都是固定的,存儲每列火車的座位的數據表沒什么可說的.
至于座位分配,可以在車票表里增加一個"已售座位"的字段.
用戶成功購票時,從"待售座位"中取一個分配給用戶并更新"已售座位"字段.
"待售座位"為"所有座位"去掉相關路段"已售座位"后的座位.
SET AUTOCOMMIT=0;
BEGIN;
SELECT 已售,已售座位 FROM 車票表
WHERE 車次=1024 AND 路段 IN ('1,2,3', '1,2,3,4', '2,3', '2,3,4', '3,4') FOR UPDATE;
UPDATE 車票表 SET 已售=(已售+1), 已售座位=CONCAT(已售座位,分配座位)
WHERE 車次=1024 AND 路段='2,3,4';
COMMIT;
SET AUTOCOMMIT=1;
其中CONCAT相比直接賦值,能夠減少傳遞給MySQL的數據量.
車票表中"已售座位"字段存儲"座位編號".
座位表: 座位編號, 列車, 車廂, 座位
總結
以上是生活随笔為你收集整理的php购票排位_用PHP+MySQL实现12306购票和退票以及余票查询逻辑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中求二维数组元素之和_乘以二
- 下一篇: 英伟达召开2023春季GTC 旗下多款重