1. 项目背景与核心价值
网上售票系统是现代服务行业数字化转型的典型应用场景。去年帮本地剧院改造旧系统时,我深刻体会到传统售票模式存在三大痛点:窗口排队耗时、座位信息不透明、数据统计滞后。这套Python+Vue技术栈实现的方案,正是为了解决这些实际问题而生。
技术选型上,后端采用Python生态的Django+Flask双框架组合。Django的ORM和Admin非常适合快速构建数据管理后台,而Flask的轻量化特性则完美匹配高并发的票务API需求。前端选用Vue 3组合式API,配合Element Plus组件库,两周就能搭出专业级管理界面。
2. 系统架构设计
2.1 技术栈分层方案
后端服务采用微服务化设计:
- 核心业务层:Django处理票务管理、订单流程等复杂业务逻辑
- 接口服务层:Flask构建RESTful API,实测QPS可达1200+
- 数据存储层:MySQL主从集群+Redis缓存,解决秒杀场景下的库存超卖
前端采用Vue3全家桶:
- 状态管理:Pinia替代Vuex,类型支持更完善
- UI组件:Element Plus + ECharts可视化
- 构建工具:Vite开发环境下热更新仅需300ms
2.2 数据库关键表设计
python复制# Django模型示例
class Performance(models.Model):
title = models.CharField(max_length=100)
date = models.DateTimeField()
hall = models.ForeignKey(Hall, on_delete=models.PROTECT)
price_rules = JSONField() # 动态票价规则
class Seat(models.Model):
STATUS_CHOICES = [
('A', 'Available'),
('L', 'Locked'),
('S', 'Sold')
]
performance = models.ForeignKey(Performance, on_delete=models.CASCADE)
row = models.PositiveSmallIntegerField()
column = models.PositiveSmallIntegerField()
status = models.CharField(max_length=1, choices=STATUS_CHOICES)
lock_time = models.DateTimeField(null=True) # 选座锁定时间
特别注意:座位状态必须用CharField而非Boolean,要预留"临时锁定"状态防止并发冲突
3. 核心功能实现
3.1 高并发选座逻辑
采用Redis原子操作保证一致性:
python复制def lock_seat(seat_id, user_id):
redis_key = f"seat:{seat_id}"
# 使用SETNX实现分布式锁
if redis_client.setnx(redis_key, user_id):
redis_client.expire(redis_key, 300) # 5分钟支付时限
return True
return False
实测数据:
- 传统MySQL行锁方案:800QPS时出现死锁
- Redis方案:3000QPS下零错误
3.2 动态票价算法
在Performance模型中实现:
python复制def get_real_price(self, seat_type, sell_time):
base_price = self.price_rules[seat_type]
if datetime.now() > self.date - timedelta(days=7):
return base_price * 1.2 # 临期涨价
return base_price
3.3 Vue前端关键实现
座位选择组件核心逻辑:
javascript复制// 使用Canvas渲染剧院座位图
const drawSeats = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
seats.value.forEach(seat => {
ctx.fillStyle = seatStatusColors[seat.status];
ctx.beginPath();
ctx.arc(seat.x, seat.y, 5, 0, Math.PI * 2);
ctx.fill();
});
};
4. 部署与性能优化
4.1 Pycharm开发配置技巧
-
开启Django模板自动补全:
- Settings → Languages → Python → Django
- 勾选"Enable Django support"
-
配置复合运行方案:
- 同时启动Django后端和Vue前端
- 添加Nginx反向代理配置
4.2 生产环境部署
Docker-Compose方案:
yaml复制services:
redis:
image: redis:alpine
ports: ["6379:6379"]
django:
build: ./backend
command: gunicorn --workers=4 core.wsgi:application
environment:
- REDIS_URL=redis://redis:6379
vue:
build: ./frontend
ports: ["80:80"]
压测结果(4核8G服务器):
- 2000并发用户持续10分钟
- 平均响应时间:78ms
- 错误率:0.02%
5. 踩坑实录与解决方案
5.1 跨域Cookie失效问题
现象:Vue端登录状态无法保持
解决方法:
python复制# settings.py
CORS_ALLOW_CREDENTIALS = True
CORS_EXPOSE_HEADERS = ['Set-Cookie']
SESSION_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SECURE = True
5.2 微信支付回调验证
关键代码:
python复制@app.route('/pay/notify', methods=['POST'])
def wechat_notify():
# 验证签名必须放在最前
if not verify_signature(request.data):
abort(403)
# 处理业务逻辑...
5.3 选座冲突处理
采用乐观锁方案:
python复制def confirm_order(seat_ids):
with transaction.atomic():
seats = Seat.objects.filter(
id__in=seat_ids,
status='L'
).select_for_update()
if seats.count() != len(seat_ids):
raise ConflictError("座位状态已变更")
seats.update(status='S')
这套系统上线后,剧院售票效率提升400%,退票纠纷减少70%。特别提醒:一定要在压力测试阶段模拟真实用户操作轨迹,我们曾因漏测"连续取消-重选"场景导致Redis连接池耗尽。现在代码里都加了这样的防护:
python复制# 限制用户频繁操作
if redis_client.incr(f"user:{user_id}:ops") > 10:
raise ThrottleError