铁路购票系统中的数据库技术《一》

2024-08-03 14:57:42 浏览数 (3)

【纪录片】中国数据库前世今生

在数字化潮流席卷全球的今天,数据库作为IT技术领域的“活化石”,已成为数字经济时代不可或缺的基础设施。那么,中国的数据库技术发展经历了怎样的历程?我们是如何在信息技术的洪流中逐步建立起自己的数据管理帝国的呢?腾讯云将邀请亲历数据库技术在中国从落地生根到蓬勃发展的技术专家们,与大家共同回顾中国数据库发展史上的重要时刻。 《中国数据库前世今生》纪录片共分为五期,从1980年代数据库在中国的起步,1990年代多家竞争的混沌,2000年代数据库的分型和国产数据库的开端,2010年代大数据席卷市场,到2020年代国产数据库的“百团大战”......每一期将深入探讨一个时代的数据库演变历程,以及这些大趋势下鲜为人知的小故事。2024年6月20日起,每双周四更新1期。点此前往查看>>《中国数据库前世今生》

今天,我们将一同探索一个与我们日常生活密切相关的话题:铁路买票系统背后的数据库技术。虽然这个主题听起来可能有些复杂,但请不用担心,我会用通俗易懂的语言,一步步地为你揭开它的神秘面纱。让我们一起踏上这趟数据库技术的列车之旅吧!

理解铁路买票系统的挑战

首先了解一下铁路买票系统面临的主要挑战:

  • 海量数据:需要处理数以亿计的乘客信息和车次信息。
  • 高并发:特别是在节假日期间,系统需要同时处理大量的查询和购票请求。
  • 实时性:票务信息需要实时更新,确保乘客获取的是最新信息。
  • 数据一致性:不能出现超卖或者票数不一致的情况。
  • 系统可用性:系统需要 24/7 全天候运行,不能出现宕机。
  • 安全性:需要保护乘客的个人信息和交易数据。

这些挑战都直接或间接地与数据库技术相关。现在,让我们逐步了解应对这些挑战的技术方案。

比如我们需要知道下列信息:

用户(电话号码,密码,身份证号,邮箱,真实姓名,用户类型,性别,地址)

乘客(用户电话号码,乘客身份证号,乘客真实姓名,乘客电话号码,乘客类型,地址)

列车信息(列车编号,车次,列车类型,列车车厢数,列车始发站,列车终点站,列车开车时间,列车到达时间,列车到达日期,列车运行时间,列车状态)

列车座位信息(列车编号,车厢号,座位类型,座位数)

列车经停信息(列车编号,车次,车站编号,车站名,到达时间,总运行时间,开车时间)

订单信息(订单编号,用户电话号码,乘客身份证号码,列车编号,出发站编号,到达站编号,车厢号,座位编号,订单创建时间,订单状态,开车时间)

数据库选型:关系型数据库的主导地位

与许多现代系统不同,铁路买票系统在很大程度上仍然依赖于关系型数据库。这是因为:

  • 数据的结构化程度高:车次、座位、乘客信息等都有明确的结构。
  • 事务的重要性:购票过程需要保证原子性、一致性、隔离性和持久性(ACID特性)。
  • 复杂查询的需求:如查找最优路径、多条件组合查询等。

常用的关系型数据库包括Oracle、MySQL、PostgreSQL等。但这并不意味着完全排斥NoSQL数据库,在某些特定场景下(如缓存),NoSQL数据库也能发挥重要作用。

数据库分片:应对海量数据

随着铁路网络的扩大和乘客数量的增加,单一的数据库服务器已经无法满足需求。这时,我们需要引入数据库分片技术

想象一下,如果我们要管理全国所有的火车票,我们可以按照地理位置进行分片。例如:

  • 华北地区的数据存储在一组服务器上
  • 华东地区的数据存储在另一组服务器上
  • 以此类推

这样做有几个好处:

  • 提高性能:每个分片只需要处理一部分数据,大大提高了查询和处理速度。
  • 增强可扩展性:当某个地区的数据量增加时,我们可以单独为该分片增加资源。
  • 提高可用性:即使一个分片出现问题,其他分片仍然可以正常工作。

主从复制:提高系统可用性

铁路买票系统需要 24/7 全天候运行,不能出现单点故障。为此,我们可以采用主从复制技术

想象有一位老师在讲课,同时有多名助教在不同的教室向学生转播这堂课。这就是主从复制的基本思想。

在数据库中:

  • 主数据库负责处理所有的写操作(如购票、退票)。
  • 从数据库负责处理读操作(如查询车次信息)。
  • 主数据库的更新会实时同步到从数据库。

这样做的好处是:

  • 提高了系统的读取性能,因为读操作被分散到多个从数据库。
  • 增强了系统的可用性,即使主数据库出现故障,从数据库也可以继续提供服务。

数据库索引:加速查询

在铁路买票系统中,快速的查询速度至关重要。这时,合理使用数据库索引可以大大提升查询性能。

想象你在查阅一本厚重的字典,如果没有目录,你需要一页页翻阅才能找到所需的词。而有了目录(索引),你就可以快速定位到所需的页面。数据库索引的作用就类似于此。

在实际应用中,我们可能会为以下字段创建索引:

  • 车次号
  • 出发站和到达站
  • 出发时间
  • 乘客身份证号

但要注意,索引虽然能够加速查询,但会占用额外的存储空间,并且会降低写入性能。因此,需要在查询性能和写入性能之间找到平衡。

关键sql语句设计

(1)根据车次查询列车所有经停站信息

代码语言:txt复制
select   b.station_no as 车站编号 ,b.station_name as  车站名, 
           b.train_number as 车次 , b.start_time  as 开车时间, 
           b.arrive_time as 到达时间 , b.running_time  as 历时 
                 from train_parking_station(列车经停站信息表) as a ,train_parking_station  as b 
                         where a.train_number = '车次'   and a.train_no = b.train_no 
                                   order by b.station_no

(2)根据起始站,目的站查询符合条件的列车

代码语言:txt复制
select C.train_no as 列车编号 ,C.train_number as 车次 ,
         C.station_name as 起始站 ,D.station_name as 目的站 ,             
         C.station_no as 起始站编号 , D.station_no as  目的站编号  ,
         C.start_time as 开车时间 , D.arrive_time as 到达时间,             
         C.running_time as 到起始站已运行时间 ,D.running_time as 到目的站已运行时间             
         from train_parking_station(列车经停站信息表) as C ,train_parking_station as D 
         where C.train_no = D.train_no 
         and C.station_name ='济南西'
         and D.station_name = '上海虹桥'     
         and C.station_no <  D.station_no        
         and C.train_no in
         (select train_no 
                   from   train_info        
                 where  train_running_type = '正在运行')

(3)根据起始站,目的站查询符合条件的列车

代码语言:txt复制
select C.train_no as 列车编号 ,C.train_number as 车次 ,
         C.station_name as 起始站 ,D.station_name as 目的站 ,             
         C.station_no as 起始站编号 , D.station_no as  目的站编号  ,
         C.start_time as 开车时间 , D.arrive_time as 到达时间,             
         C.running_time as 到起始站已运行时间 ,D.running_time as 到目的站已运行时间             
         from train_parking_station(列车经停站信息表) as C ,train_parking_station as D 
         where C.train_no = D.train_no 
         and C.station_name ='济南西'
         and D.station_name = '上海虹桥'     
         and C.station_no <  D.station_no        
         and C.train_no in
         (select train_no 
                   from   train_info        
                 where  train_running_type = '正在运行')

(4)根据起始站,目的站查询换乘的列车

代码语言:txt复制
select A.train_no as 列车-1编号 ,A.train_number as 列车-1车次, D.train_no as 列车-2编号 ,
         D.train_number as 列车-2车次, A.station_no as 起始站编号,
         A.station_name as 起始站名称, B.station_no as 列车-1换乘站编号 , 
         B.station_name as 列车-1换乘站名称 ,C.station_no as 列车-2换乘站编号,
         D.station_no as 目的站编号,  D.station_name as 目的站名称,
         A.start_time as 列车-1发车时间 , B.arrive_time as 列车-1到达时间, 
         C.start_time as 列车-2发车时间 ,D.arrive_time as 列车-2到达时间 
         from  train_parking_station as A , train_parking_station as B , 
                  train_parking_station as C ,train_parking_station as D 
                  where A.station_name = '哈尔滨' and D.station_name = '广州' 
                           and B.station_name = C.station_name 
                           and   A.train_no = B.train_no  and C.train_no = D.train_no and B.train_no <> C.train_no   
                           and B.arrive_time < C.arrive_time  
                           and  A.station_no <B.station_no and C.station_no<D.station_no
                           and A.train_no  in (select train_no from train_info where train_running_type = '正在运行')
                           and C.train_no in  (select train_no from train_info where train_running_type = '正在运行')

(5)根据起始站编号,目的站编号,列车编号查询列车途中经停车站

代码语言:txt复制
select A.train_no as 列车编号, A.train_number as 车次 ,
         A.station_name as 起始站 ,B.station_name as 目的站, 
         A.station_no as 经停站-1编号 , B.station_no as 经停站-2编号 ,
         A.start_time as 开车时间 , B.arrive_time as 到达时间,
         A.running_time as 到经停站-1已运行时间 ,B.running_time as 到经停站-2已运行时间 
         from train_parking_station as A ,train_parking_station as B 
         where A.station_no between '起始站编号' and '目的站编号'
         and  B.station_no between '起始站编号' and '目的站编号'
         and A.train_no = '列车编号'                
         and A.train_no = B.train_no 
         and B.station_no = A.station_no  1 order by A.station_no ,B.station_no 

0 人点赞