1. 项目概述
这个火车票订票系统采用SpringBoot+Vue+MySQL技术栈实现,是一个典型的前后端分离架构项目。我在实际开发中发现,这类系统最核心的挑战在于如何处理高并发订票请求和保证数据一致性。系统包含用户管理、车次查询、余票显示、订单管理、支付对接等完整功能模块,前后端代码结构清晰,数据库设计规范,确实可以直接运行调试。
2. 技术架构解析
2.1 后端技术选型
SpringBoot 2.7.x作为后端框架,主要基于以下考虑:
- 自动配置特性简化了SSM框架整合
- 内嵌Tomcat方便直接运行
- Actuator端点提供系统监控能力
- 与MyBatis-Plus配合实现高效数据访问
数据库选用MySQL 8.0,关键配置参数:
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/train_ticket?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
2.2 前端技术方案
Vue 3.x + Element Plus构建管理后台,主要特点:
- 基于Composition API的组件化开发
- Axios封装了RESTful API调用
- Vue Router实现前端路由控制
- Pinia状态管理替代Vuex
注意:开发环境需配置proxy解决跨域问题,生产环境应通过Nginx反向代理
3. 核心功能实现
3.1 余票查询模块
采用Redis缓存车次余票信息,关键数据结构设计:
java复制// 车次座位缓存key设计
String key = "train:stock:" + trainNumber + ":" + date;
// 使用Hash结构存储不同席别余量
redisTemplate.opsForHash().put(key, "business", 50);
redisTemplate.opsForHash().put(key, "first", 100);
3.2 订单创建流程
- 前端提交订单请求
- 后端校验用户登录状态
- 分布式锁防止重复提交
- 数据库事务处理:
- 扣减余票
- 生成订单记录
- 创建支付预订单
- 返回订单编号给前端
java复制@Transactional
public String createOrder(OrderDTO orderDTO) {
// 1. 获取分布式锁
String lockKey = "order:lock:" + orderDTO.getUserId();
boolean locked = redisLock.tryLock(lockKey, 10, TimeUnit.SECONDS);
try {
// 2. 校验余票
checkTicketStock(orderDTO);
// 3. 扣减库存
reduceTicketStock(orderDTO);
// 4. 生成订单
Order order = buildOrder(orderDTO);
orderMapper.insert(order);
// 5. 创建支付记录
createPayment(order);
return order.getOrderNo();
} finally {
redisLock.unlock(lockKey);
}
}
4. 数据库设计要点
4.1 主要表结构
| 表名 | 字段 | 说明 |
|---|---|---|
| train_info | id, train_no, start_station, end_station... | 车次基础信息 |
| train_schedule | id, train_id, station_name, arrive_time... | 车次时刻表 |
| ticket_stock | id, train_id, date, seat_type, amount... | 余票库存 |
| order_info | order_no, user_id, train_id, status... | 订单主表 |
| order_detail | id, order_no, passenger_id, seat_type... | 订单明细 |
4.2 索引优化方案
- 车次查询相关表添加复合索引:
sql复制ALTER TABLE train_info ADD INDEX idx_number (train_no); ALTER TABLE train_schedule ADD INDEX idx_train_station (train_id, station_name); - 订单表按用户ID和创建时间分片
- 余票表使用日期+车次ID作为主键
5. 部署运行指南
5.1 后端启动步骤
- 导入Maven项目
- 创建MySQL数据库并执行init.sql
- 修改application.yml中的数据库配置
- 启动Redis服务
- 运行SpringBoot主类
5.2 前端启动流程
- 安装Node.js 16+
- 执行npm install安装依赖
- 配置.env.development环境变量
- npm run dev启动开发服务器
6. 常见问题解决
-
日期格式化问题:
javascript复制// 前端处理方案 dayjs(date).format('YYYY-MM-DD') // 后端处理方案 @JsonFormat(pattern = "yyyy-MM-dd") private Date travelDate; -
高并发下超卖问题:
- 使用Redis原子操作扣减库存
- 数据库乐观锁控制
java复制UPDATE ticket_stock SET amount = amount - 1 WHERE train_id = ? AND date = ? AND amount > 0 -
支付状态同步:
- 支付宝/微信支付回调处理
- 定时任务补偿查询
- 消息队列异步通知
7. 性能优化建议
- 前端采用懒加载和分页查询
- 后端接口添加二级缓存
- 静态资源走CDN加速
- Nginx配置Gzip压缩
- 数据库读写分离部署
我在实际项目中发现,当余票查询QPS超过500时,需要特别注意Redis集群的部署方案。建议采用Redis Cluster模式,同时合理设置过期时间避免缓存雪崩。对于订单创建这类核心业务,一定要做好分布式事务处理,我们最终采用的方案是Seata AT模式配合本地消息表。
