1. 项目背景与核心需求
医疗资源分配不均一直是社会痛点问题。去年陪家人看病的经历让我深刻体会到传统挂号方式的弊端——凌晨排队、号源紧张、信息不透明。这正是我选择开发医生预约系统作为毕业设计的初衷。
这个系统要解决三个核心问题:
- 消除患者与医生之间的信息差,实现号源可视化
- 通过线上流程减少现场排队时间
- 建立医患双向评价机制提升服务质量
系统采用B/S架构,前端使用Vue+Element UI实现响应式布局,后端基于Spring Boot+MyBatis技术栈,数据库选用MySQL 8.0。特别针对三甲医院的门诊场景做了优化,支持每秒200+的并发预约请求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计解析
2.1 微服务模块划分
系统采用领域驱动设计(DDD)思想,将核心业务拆分为四个微服务:
- 用户服务:处理患者/医生注册、登录、权限管理
- 排班服务:管理医生出诊时间、号源生成规则
- 预约服务:处理预约创建、支付、取消等事务
- 评价服务:收集和分析医患互评数据
每个服务独立部署,通过Spring Cloud Alibaba的Nacos实现服务发现,Feign完成服务间调用。这种设计在毕业答辩时获得了评委的高度认可,认为其符合现代医疗系统的演进方向。
2.2 数据库关键表设计
核心表结构经过三次迭代优化:
sql复制CREATE TABLE `doctor_schedule` (
`id` bigint NOT NULL AUTO_INCREMENT,
`doctor_id` bigint NOT NULL COMMENT '关联医生ID',
`hospital_id` int NOT NULL,
`department_id` int NOT NULL COMMENT '科室ID',
`schedule_date` date NOT NULL,
`time_period` varchar(20) NOT NULL COMMENT '时段(上午/下午/晚上)',
`total_count` int DEFAULT '30' COMMENT '总号源数',
`remaining_count` int DEFAULT '0',
`status` tinyint DEFAULT '1' COMMENT '1有效 0停诊',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_doctor_date_period` (`doctor_id`,`schedule_date`,`time_period`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
这个设计解决了初期遇到的号源超卖问题,通过联合唯一索引确保同一医生同时间段只能有一条排班记录,剩余号源字段采用乐观锁控制并发更新。
3. 核心技术实现细节
3.1 高并发预约控制
采用Redis+Lua脚本实现分布式锁,关键代码片段:
java复制public boolean tryLock(String lockKey, String requestId, int expireTime) {
String luaScript = "if redis.call('exists', KEYS[1]) == 0 then " +
"redis.call('hset', KEYS[1], ARGV[1], 1); " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 1; " +
"end; " +
"return 0;";
Long result = (Long) redisTemplate.execute(
new DefaultRedisScript<>(luaScript, Long.class),
Collections.singletonList(lockKey),
requestId, String.valueOf(expireTime));
return result != null && result == 1;
}
配合@Transactional注解确保业务原子性,实测在4核8G服务器上可稳定处理250+ TPS。这里有个坑要注意:Redis锁过期时间要大于业务执行最长时间,否则会出现锁提前释放导致数据不一致。
3.2 动态排班规则引擎
为适应不同医院的排班习惯,开发了基于Groovy的规则引擎:
groovy复制// 每周一上午、周三全天出诊
if(['MON'].contains(dayOfWeek) && period=='AM') return true
if(['WED'].contains(dayOfWeek)) return true
return false
规则配置存储在MongoDB中,支持热更新。这个设计让系统可以快速适配不同医院的排班政策,在演示时通过修改规则实时生成不同的医生排班表,成为答辩亮点。
4. 典型问题排查实录
4.1 跨院区号源同步异常
上线测试时发现:当医生在总院和分院同时出诊时,分院号源更新会覆盖总院数据。通过分析MySQL binlog发现是MyBatis的乐观锁版本号更新策略有问题。
解决方案:
- 为不同院区创建独立的排班记录
- 在service层添加院区校验逻辑
- 前端展示时按院区分组
这个坑耗费了整整两天排查,教训是:涉及多租户的数据操作必须从业务层面做好隔离,不能依赖技术层面的乐观锁。
4.2 定时任务堆积问题
凌晨批量生成号源的任务经常执行超时。通过Arthas工具追踪发现是MyBatis的N+1查询问题:
优化前:查询所有医生→逐个查询科室信息
优化后:改用联合查询+ResultMap映射
xml复制<resultMap id="doctorWithDept" type="Doctor">
<id property="id" column="d_id"/>
<result property="name" column="d_name"/>
<association property="department" javaType="Department">
<id property="id" column="dept_id"/>
<result property="name" column="dept_name"/>
</association>
</resultMap>
优化后任务执行时间从47分钟降到3分钟。关键收获:批量处理场景要特别注意ORM框架的使用方式。
5. 项目部署与扩展建议
系统采用Docker Compose部署方案,包含以下服务:
- 前端:nginx:alpine镜像
- 后端:基于openjdk:11构建的多阶段镜像
- 中间件:Redis哨兵集群+MySQL主从
对于想继续开发的同学,建议从三个方向扩展:
- 接入微信/支付宝小程序提升患者使用体验
- 增加智能分诊功能,基于症状推荐科室
- 开发医生端APP支持移动办公
源码已托管在Gitee(为避免审核问题不展示具体链接),包含完整的API文档和Postman测试集合。在开发过程中最大的体会是:医疗系统对数据一致性和可靠性的要求远超普通电商系统,每个设计决策都要经过充分的异常场景测试。
