PHP设计12306.cn (转载)

2024-04-10 05:18
文章标签 设计 php 转载 12306 cn

本文主要是介绍PHP设计12306.cn (转载),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在知乎上看到的问题与答案,觉得非常值得学习与思考,在此记录一下:
值得注意的是原答主忽略了一种购票逻辑,我咨询后,答主也同意我的想法。
这里写图片描述

原答案:

举例说明,用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]的路段如[1,2,3,4]已售的票,
以及[2,3,4]包含的子路段如[2,3]和[3,4]已售的票,
如果三者的票合计小于500(这里假设列车满载为500人),
则用户能够购票,即[2,3,4]这个路段已售的票数+1.

SQL购票逻辑如下(以MySQL为例):

SET AUTOCOMMIT=0;
START TRANSACTION;BEGIN; --开启事务
SELECT 已售 FROM 车票表 WHERE 车次=1024
AND 路段 IN ('2,3,4', '2,3', '3,4', '1,2,3,4') FOR UPDATE;
UPDATE 车票表 SET 已售=(已售+1) WHERE 车次=1024 AND 路段='2,3,4';
COMMIT; --提交事务
SET AUTOCOMMIT=1;

上述购票逻辑,关键在于找到WHERE条件IN中的路段,步骤如下:

1.找出包含一个路段如[2,3,4]的其他路段:
SELECT 路段 FROM 车票表 WHERE 车次=1024 AND 路段 LIKE ‘%2,3,4%’;
一个车次至多也就包含几百个路段,所以LIKE模糊查询几百条记录性能完全可以接受.
在本例中得到:
[1,2,3,4]

2.找出一个路段如[2,3,4]里的子路段算法(以PHP为例):

function section(array $arr, array &$tmp) {
$size = count($arr);
if ($size == 1) return;
for ($i = 2; $i <= $size; $i++) {
// 从位置0开始,取$i个元素,不影响输入的数组.
$tmp[] = array_slice($arr, 0, $i);
}
array_shift($arr); // 删除数组开头元素
section($arr, $tmp); // 递归
}
$arr = array(2,3,4);
$tmp = array();
section($arr, $tmp);
var_export($tmp);

在本例中得到:
[2,3]
[2,3,4]
[3,4]
第一轮得到[2,3],[2,3,4],摘掉头元素2进行下一轮.
第二轮得到[3,4],摘掉头元素3进行下一轮.
当数组元素数量等于1时,结束递归.
优化:跟某个路段相关的路段其实可以事先计算出来保存起来.

极端车次: 深圳北-北京北 K106车次 途径26站

echo implode(',', range(1, 26));
找出路段[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]的子路段:
$tmp = array();
section(range(1, 26), $tmp);
foreach ($tmp as &$v) {
$v = implode(',', $v);
$v = "[{$v}]";
}
var_export($tmp);

当购买起点站到终点站的车票时,路段IN查询中有326个条件,因为26个站包含325个子路段.
也就是该车次的所有路段都会被SELECT FOR UPDATE锁定.
不过这时可以不用路段IN条件进行锁定,直接用车次字段进行锁定即可.

退票逻辑:
退票逻辑比购票逻辑简单得多,直接给对应车次,对应路段的已售车票-1即可:
UPDATE 车票表 SET 已售=(已售-1) WHERE 车次=1024 AND 路段=’2,3,4’;

余票查询逻辑:
例如查询车次1024上路段[2,3,4]的余票:
SELECT 已售 FROM 车票表 WHERE 车次=1024 AND 路段 IN (‘2,3,4’, ‘2,3’, ‘3,4’, ‘1,2,3,4’);
这里假设列车满载为500人,用500减去上述路段已售车票的和就是路段[2,3,4]上的余票.
可以使用MySQL内存表或Redis缓存余票查询结果,购票和退票时更新缓存.

座位分配逻辑:
一列火车,其座位都是固定的,存储每列火车的座位的数据表没什么可说的.
至于座位分配,可以在车票表里增加一个”已售座位”的字段.
用户成功购票时,从”待售座位”中取一个分配给用户并更新”已售座位”字段.
“待售座位”为”所有座位”去掉相关路段”已售座位”后的座位.

SET AUTOCOMMIT=0;
BEGIN;
SELECT 已售,已售座位 FROM 车票表
WHERE 车次=1024 AND 路段 IN ('2,3,4', '2,3', '3,4', '1,2,3,4') FOR UPDATE;
UPDATE 车票表 SET 已售=(已售+1), 已售座位=CONCAT(已售座位,分配座位)
WHERE 车次=1024 AND 路段='2,3,4';
COMMIT;
SET AUTOCOMMIT=1;

其中CONCAT相比直接赋值,能够减少传递给MySQL的数据量.
车票表中”已售座位”字段存储”座位编号”.
座位表: 座位编号, 列车, 车厢, 座位

纠错内容:
补充(纠错):经评论里的网友提醒,纠错如下:应该找出跟目标路段[2,3,4]有交集(相交元素>=2)的路段,比如还包括[1,2,3].算法如下:

<?php
$all = array(1,2,3,4);
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]

作者:eechen
链接:https://www.zhihu.com/question/20017917/answer/268401471
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这篇关于PHP设计12306.cn (转载)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/890154

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

SprinBoot+Vue网络商城海鲜市场的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质创作者,全网30w+

单片机毕业设计基于单片机的智能门禁系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订

Spring的设计⽬标——《Spring技术内幕》

读《Spring技术内幕》第二版,计文柯著。 如果我们要简要地描述Spring的设计⽬标,可以这么说,Spring为开发者提供的是⼀个⼀站式的轻量级应⽤开发框架(平台)。 作为平台,Spring抽象了我们在 许多应⽤开发中遇到的共性问题;同时,作为⼀个轻量级的应⽤开发框架,Spring和传统的J2EE开发相⽐,有其⾃⾝的特点。 通过这些⾃⾝的特点,Spring充分体现了它的设计理念:在

开题报告中的研究方法设计:AI能帮你做什么?

AIPaperGPT,论文写作神器~ https://www.aipapergpt.com/ 大家都准备开题报告了吗?研究方法部分是不是已经让你头疼到抓狂? 别急,这可是大多数人都会遇到的难题!尤其是研究方法设计这一块,选定性还是定量,怎么搞才能符合老师的要求? 每次到这儿,头脑一片空白。 好消息是,现在AI工具火得一塌糊涂,比如ChatGPT,居然能帮你在研究方法这块儿上出点主意。是不

创业者该如何设计公司的股权架构

本文来自七八点联合IT橘子和车库咖啡的一系列关于设计公司股权结构的讲座。 主讲人何德文: 在公司发展的不同阶段,创业者都会面临公司股权架构设计问题: 1.合伙人合伙创业第一天,就会面临股权架构设计问题(合伙人股权设计); 2.公司早期要引入天使资金,会面临股权架构设计问题(天使融资); 3.公司有三五十号人,要激励中层管理与重要技术人员和公司长期走下去,会面临股权架构设计问题(员工股权激

PHP原理之内存管理中难懂的几个点

PHP的内存管理, 分为俩大部分, 第一部分是PHP自身的内存管理, 这部分主要的内容就是引用计数, 写时复制, 等等面向应用的层面的管理. 而第二部分就是今天我要介绍的, zend_alloc中描写的关于PHP自身的内存管理, 包括它是如何管理可用内存, 如何分配内存等. 另外, 为什么要写这个呢, 因为之前并没有任何资料来介绍PHP内存管理中使用的策略, 数据结构, 或者算法. 而在我们

php中json_decode()和json_encode()

1.json_decode() json_decode (PHP 5 >= 5.2.0, PECL json >= 1.2.0) json_decode — 对 JSON 格式的字符串进行编码 说明 mixed json_decode ( string $json [, bool $assoc ] ) 接受一个 JSON 格式的字符串并且把它转换为 PHP 变量 参数 json