1. 项目概述:当SSM框架遇上航空票务系统
航空票务系统作为典型的高并发在线交易场景,对系统的稳定性、安全性和响应速度都有着严苛要求。这个基于SSM框架的飞机订票系统,不仅实现了基础的航班查询、座位选择和支付功能,还创新性地引入了协同过滤算法来提供个性化推荐服务。在实际开发中,我们发现这种技术组合能够很好地平衡开发效率和系统性能。
SSM(Spring+SpringMVC+MyBatis)作为JavaEE开发的经典框架组合,其分层架构设计特别适合票务系统这类业务逻辑复杂的项目。Spring的IoC容器管理着从数据访问层到业务层的所有Bean,SpringMVC处理前端请求的路由和响应,而MyBatis则负责与MySQL数据库的交互。这种架构使得系统在面对航空公司频繁的票价调整、航班变更等业务需求时,能够保持足够的灵活性和可维护性。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统核心架构解析
2.1 SSM框架的技术选型考量
选择SSM框架而非SpringBoot等新框架,主要基于以下几个实际考量:
- 控制粒度更精细:在票务系统中,我们需要精确控制数据库连接池大小、事务隔离级别等参数,SSM的XML配置方式比SpringBoot的自动配置更直观
- 遗留系统兼容性:很多航空公司的现有系统仍在使用传统架构,SSM更容易与这些系统对接
- 团队技术储备:国内大多数Java团队对SSM的掌握程度更深
数据库设计方面,我们采用了分表策略:
- 航班信息表(flight_info)按航空公司ID分表
- 订单表(ticket_order)按用户ID哈希分表
- 座位库存表(seat_inventory)使用Redis缓存
2.2 协同过滤算法的实现方案
系统实现了两种推荐算法:
- 基于用户的协同过滤(UserCF):
java复制public List<Flight> recommendByUserCF(User user) {
// 1. 找出相似用户
List<User> similarUsers = userSimilarityService.findTopN(user, 10);
// 2. 获取这些用户的购票记录
List<Flight> flights = orderService.getFlightsByUsers(similarUsers);
// 3. 过滤掉当前用户已购买的航班
return filterService.filterPurchased(flights, user);
}
- 基于物品的协同过滤(ItemCF):
java复制public List<Flight> recommendByItemCF(Flight flight) {
// 1. 计算航班相似度矩阵
Map<Flight, Double> similarityMatrix = flightSimilarityService.buildMatrix();
// 2. 获取最相似的航班
return similarityMatrix.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.limit(5)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
实际运行中,我们发现UserCF在用户量达到10万时会出现性能瓶颈,因此增加了以下优化:
- 使用MinHash算法降低相似度计算复杂度
- 对用户分群进行离线计算
- 引入Guava Cache缓存最近访问的用户数据
3. 关键业务模块实现细节
3.1 高并发座位锁定机制
票务系统最核心也最容易出问题的就是座位库存管理。我们设计了三级库存校验机制:
- 前端限流:使用RateLimiter控制查询请求频率
- 中间层校验:Redis分布式锁+库存缓存
java复制public boolean lockSeat(String flightNo, String seatNo) {
String lockKey = "lock:" + flightNo + ":" + seatNo;
// 尝试获取分布式锁
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (locked) {
try {
// 检查真实库存
Integer stock = seatStockMapper.selectStock(flightNo, seatNo);
if (stock > 0) {
// 扣减库存
return seatStockMapper.decreaseStock(flightNo, seatNo) > 0;
}
} finally {
redisTemplate.delete(lockKey);
}
}
return false;
}
- 数据库最终校验:通过SELECT FOR UPDATE确保一致性
3.2 交易支付流程设计
支付流程采用了TCC(Try-Confirm-Cancel)模式处理分布式事务:
- Try阶段:预扣减库存,生成待支付订单
- Confirm阶段:
- 调用支付网关
- 更新订单状态
- 发送出票消息
- Cancel阶段:
- 恢复库存
- 取消订单
- 记录失败日志
我们使用RabbitMQ实现异步消息通知,关键配置如下:
xml复制<bean id="orderMessageListener" class="com.airline.listener.OrderMessageListener"/>
<rabbit:listener-container connection-factory="connectionFactory">
<rabbit:listener ref="orderMessageListener"
method="handleMessage"
queue-names="order.queue"/>
</rabbit:listener-container>
4. 性能优化实战经验
4.1 数据库查询优化
航班查询是最频繁的操作,我们通过以下手段提升性能:
-
多级缓存策略:
- 热点航班信息缓存在Redis
- 用户个人查询历史使用本地Caffeine缓存
- 静态数据(如机场信息)缓存在Ehcache
-
SQL优化示例:
java复制@Select("SELECT f.* FROM flight_info f " +
"WHERE f.departure_airport = #{departure} " +
"AND f.arrival_airport = #{arrival} " +
"AND f.departure_time BETWEEN #{startDate} AND #{endDate} " +
"ORDER BY f.departure_time ASC " +
"LIMIT 100")
List<Flight> searchFlights(@Param("departure") String departure,
@Param("arrival") String arrival,
@Param("startDate") Date startDate,
@Param("endDate") Date endDate);
配合以下索引:
sql复制CREATE INDEX idx_flight_route ON flight_info(departure_airport, arrival_airport, departure_time);
4.2 推荐算法性能调优
协同过滤算法在实际运行中遇到了几个性能瓶颈:
-
相似度计算优化:
- 将余弦相似度计算改为向量内积
- 使用SIMD指令加速矩阵运算
- 对稀疏矩阵采用CSR存储格式
-
离线+实时混合推荐:
mermaid复制graph TD
A[用户行为数据] --> B[离线计算]
A --> C[实时计算]
B --> D[用户分群模型]
C --> E[实时兴趣提取]
D --> F[推荐结果融合]
E --> F
F --> G[最终推荐列表]
- AB测试框架集成:
我们在Spring中实现了简单的AB测试路由:
java复制@Controller
public class RecommendationController {
@Autowired
private RecommendStrategyFactory factory;
@RequestMapping("/recommend")
public String recommend(HttpServletRequest request, Model model) {
User user = (User)request.getSession().getAttribute("user");
// 根据用户ID哈希决定使用哪种算法
RecommendStrategy strategy = factory.getStrategy(user.getId());
List<Flight> flights = strategy.recommend(user);
model.addAttribute("flights", flights);
return "recommendation";
}
}
5. 典型问题排查实录
5.1 库存超卖问题排查
我们曾遇到即使在Redis锁保护下仍然出现超卖的情况,经过排查发现:
-
问题根源:
- Redis锁过期时间设置过短(原为10秒)
- 支付流程中某些操作可能超过10秒
- 导致锁失效后另一个请求获取到锁
-
解决方案:
- 增加锁续期机制
- 引入Redisson的看门狗模式
- 关键代码调整:
java复制// 使用Redisson客户端替代原生RedisTemplate
RLock lock = redissonClient.getLock(lockKey);
try {
// 尝试加锁,最多等待100ms,锁持有时间30秒(会自动续期)
if (lock.tryLock(100, 30000, TimeUnit.MILLISECONDS)) {
// 业务逻辑
}
} finally {
lock.unlock();
}
5.2 推荐结果冷启动问题
新用户或新航班缺乏足够的行为数据时,协同过滤效果不佳。我们采用的解决方案:
-
混合推荐策略:
- 新用户:基于热门航班+随机推荐
- 新航班:基于航线相似度推荐
- 老用户:协同过滤+最近浏览
-
数据预热方案:
java复制@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
public void precomputeRecommendations() {
// 预计算所有活跃用户的推荐结果
List<User> activeUsers = userService.getActiveUsers();
activeUsers.parallelStream().forEach(user -> {
List<Flight> recommendations = recommendService.recommend(user);
redisTemplate.opsForValue().set(
"user:rec:" + user.getId(),
serialize(recommendations),
24, TimeUnit.HOURS);
});
}
6. 安全防护方案
航空票务系统面临的主要安全威胁包括:
-
黄牛刷票防御措施:
- 基于用户行为的反爬策略
- 关键接口人机验证
- 购买频率限制(同一IP/设备/账号)
-
支付安全保障:
java复制public PaymentResult processPayment(PaymentRequest request) {
// 1. 参数校验
if (!paymentValidator.validate(request)) {
throw new IllegalPaymentException("Invalid payment request");
}
// 2. 风控检查
RiskCheckResult risk = riskControlService.check(request);
if (risk.isHighRisk()) {
log.warn("高风险支付: {}", request);
return PaymentResult.fail("支付被风控拦截");
}
// 3. 支付网关调用
return paymentGateway.execute(request);
}
- 数据加密方案:
- 敏感字段(身份证、银行卡)AES加密存储
- 传输层使用HTTPS+双向证书
- 日志脱敏处理
7. 监控与运维体系
完善的监控是系统稳定运行的保障:
-
监控指标:
- 关键接口响应时间(如查询、下单)
- Redis缓存命中率
- 数据库连接池使用率
- 推荐算法计算耗时
-
告警策略:
yaml复制# Prometheus告警规则示例
groups:
- name: airline.rules
rules:
- alert: HighErrorRate
expr: rate(http_server_requests_errors_total{job="airline-web"}[5m]) > 0.1
for: 10m
labels:
severity: critical
annotations:
summary: "高错误率 ({{ $value }})"
description: "Web服务错误率超过10%"
- 日志收集方案:
- 使用ELK栈集中管理日志
- 关键业务日志(如订单状态变更)单独存储
- 推荐算法相关日志包含完整的特征向量
8. 项目部署架构
生产环境采用多机房部署方案:
-
基础架构:
- Nginx负载均衡+Keepalived高可用
- Tomcat集群(每个实例配置相同的JVM参数)
- MySQL主从复制+读写分离
- Redis哨兵模式
-
持续交付流程:
mermaid复制graph LR
A[代码提交] --> B[Jenkins构建]
B --> C[单元测试]
C --> D[打包Docker镜像]
D --> E[测试环境部署]
E --> F[自动化测试]
F --> G[生产环境灰度发布]
- 配置管理:
- 使用Apollo配置中心管理不同环境的参数
- 敏感配置加密存储
- 支持运行时配置热更新
9. 扩展性与未来演进
系统设计时预留了多个扩展点:
-
多航空公司支持:
- 通过SPI机制实现航空公司接口
- 每个航空公司实现自己的库存管理策略
- 动态加载航空公司模块
-
国际化扩展:
properties复制# 多语言资源文件示例
flight.status.delayed=航班延误
flight.status.delayed.en=Flight Delayed
flight.status.delayed.zh_CN=航班延误
- 新技术演进:
- 逐步将部分模块迁移到SpringCloud生态
- 考虑使用Flink实现实时推荐
- 探索GraphQL替代部分REST接口
在实际开发中,我们发现SSM框架虽然不如新框架"时髦",但其稳定性和可控性在航空这类传统行业非常适用。特别是当系统需要与各种遗留系统对接时,SSM的灵活配置优势就显现出来了。一个经验是:不要盲目追求新技术,适合业务场景的才是最好的。
