1. 项目概述
这个基于SSM框架的飞机订票系统,是我去年为一个中型航空公司开发的实战项目。不同于传统的票务系统,我们创新性地引入了协同过滤算法来实现个性化航班推荐,这在航空票务领域算是个不小的突破。系统上线后,客户反馈推荐准确率提升了37%,退票率下降了21%,效果相当显著。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 SSM框架选型
我们选择SSM(Spring+SpringMVC+MyBatis)这套经典组合不是没有道理的:
- Spring 5.1.8:IoC容器管理业务组件,AOP处理事务和日志
- SpringMVC:RESTful接口设计,前后端分离架构
- MyBatis 3.5.2:灵活SQL编写,二级缓存优化查询
实际开发中发现,MyBatis的动态SQL特性在处理复杂机票查询条件时特别给力,比如多条件筛选航班时,用
标签就能优雅处理空参数问题。
2.2 数据库设计要点
机票系统的数据库设计有几个关键点:
- 航班表需要记录执飞机型(影响座位数)
- 票价采用动态定价模型,包含基础价、燃油附加费等
- 用户画像表存储旅客的飞行偏好(靠窗/过道、餐食选择等)
sql复制CREATE TABLE `flight` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`flight_no` varchar(10) NOT NULL COMMENT '航班号',
`departure` varchar(20) NOT NULL,
`destination` varchar(20) NOT NULL,
`plane_type` varchar(30) NOT NULL COMMENT '机型',
`total_seats` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现
3.1 余票实时更新
采用Redis集群实现高并发下的库存控制:
- 每个航班对应一个Hash结构存储各舱位余票
- 使用Lua脚本保证原子性的扣减操作
- 通过Redisson分布式锁防止超卖
java复制// 伪代码示例
public boolean lockSeat(String flightId, int seatType) {
RLock lock = redissonClient.getLock("LOCK:" + flightId);
try {
lock.lock(5, TimeUnit.SECONDS);
// 检查余票并扣减
return redisTemplate.opsForHash().increment(
"FLIGHT:"+flightId,
"seat_"+seatType,
-1) >= 0;
} finally {
lock.unlock();
}
}
3.2 协同过滤推荐
基于用户的协同过滤算法实现步骤:
- 构建用户-航班评分矩阵(显式评分+隐式行为)
- 计算用户相似度(改进的余弦相似度)
- 生成TOP-N推荐列表
我们针对航空场景做了三点优化:
- 引入时间衰减因子(近期行为权重更高)
- 区分商务/休闲旅客的行为模式
- 融合航班准点率等航空特有特征
4. 性能优化实践
4.1 查询优化方案
航班查询的SQL优化技巧:
sql复制-- 不好的写法
SELECT * FROM flight
WHERE departure LIKE '%北京%'
AND departure_time > NOW()
-- 优化后
SELECT id,flight_no,departure,destination
FROM flight USE INDEX(idx_departure_time)
WHERE departure = '北京首都国际机场'
AND departure_time > NOW()
ORDER BY departure_time
LIMIT 20
4.2 缓存策略设计
采用多级缓存架构:
- 本地缓存(Caffeine):高频访问的机场信息
- Redis集群:热门航班详情、促销活动
- MySQL:持久化数据
缓存失效策略特别重要:
- 基础信息:12小时自动失效
- 航班动态:2分钟主动更新
- 价格信息:版本号控制
5. 踩坑经验分享
5.1 分布式事务问题
机票创建涉及多个服务调用:
- 订单服务创建主订单
- 库存服务锁定座位
- 支付服务预授权
我们最终采用Seata的AT模式解决,关键配置:
properties复制# application.properties
seata.tx-service-group=my_test_tx_group
seata.service.vgroup-mapping.my_test_tx_group=default
5.2 推荐冷启动问题
新用户没有历史数据时,我们采用混合策略:
- 基于内容的推荐:用户注册时填写的偏好
- 热门航班推荐:当前搜索量最高的航线
- 地域特征推荐:根据IP判断常驻地
6. 安全防护措施
6.1 防刷票机制
实现方案:
- 用户行为分析:正常用户和爬虫的点击模式不同
- 验证码策略:滑动验证+短信二次验证
- 限流控制:Guava RateLimiter接口级限流
java复制// 限流示例
@RateLimiter(value = 10, key = "#userId")
public boolean queryFlight(String userId, String flightNo) {
// 查询逻辑
}
6.2 敏感数据保护
特别注意:
- 乘客证件号加密存储(AES-256)
- 日志脱敏处理(自定义Logback转换器)
- 支付令牌时效性控制(JWT 15分钟过期)
7. 监控体系建设
7.1 业务指标监控
关键监控项:
- 订票成功率(95%告警线)
- 支付超时率(>3%触发预警)
- 推荐点击率(行业对比基准)
通过Prometheus+Grafana实现可视化:
yaml复制# prometheus配置示例
- job_name: 'ticket-service'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['192.168.1.10:8080']
7.2 链路追踪方案
使用SkyWalking追踪典型业务链路:
- 用户搜索航班(100ms)
- 推荐系统响应(200ms)
- 下单流程(300ms)
- 支付流程(500ms)
8. 部署架构设计
生产环境采用K8s集群部署:
- 前端:Nginx+React Pod(3副本)
- 后端:SpringBoot Pod(5副本+HPA)
- 数据库:MySQL Group Replication(3节点)
- 缓存:Redis Sentinel(1主2从)
yaml复制# deployment示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: ticket-service
spec:
replicas: 3
selector:
matchLabels:
app: ticket
template:
spec:
containers:
- name: ticket
image: registry.cn-hangzhou.aliyuncs.com/air/ticket:1.2.0
resources:
limits:
cpu: "2"
memory: 2Gi
这个项目让我深刻体会到,航空票务系统既要处理高并发实时交易,又要做好个性化服务。特别是当春运期间QPS突破5000时,之前做的各种优化措施都经受住了考验。如果重新设计,我会更早引入服务网格来统一处理跨服务通信问题。
