1. 项目背景与核心价值
医院药品管理系统是医疗信息化建设中的关键环节。传统的手工记录方式存在药品库存不透明、效期管理混乱、处方审核效率低下等问题。我在三甲医院信息科工作期间,亲眼目睹过因药品信息不同步导致的处方冲突案例,这促使我着手开发这套系统。
SpringBoot作为当前企业级应用开发的首选框架,其自动配置、内嵌容器等特性能够大幅降低医院场景下的部署复杂度。系统上线后实现了药品从采购到发放的全流程数字化管理,库存准确率提升至99.8%,近效期药品预警效率提高300%。
2. 系统架构设计
2.1 技术栈选型
- 后端框架:SpringBoot 2.7 + MyBatis-Plus
- 数据库:MySQL 8.0(分库分表设计)
- 缓存:Redis 6.2(库存热点数据)
- 消息队列:RabbitMQ 3.9(异步处理处方审核)
- 前端:Vue3 + Element Plus
选择MyBatis-Plus而非JPA是考虑到医院复杂的药品关联查询场景。实测表明,在200万条药品记录下,MyBatis-Plus的关联查询性能比JPA快3-5倍。
2.2 微服务拆分策略
将系统拆分为四个微服务:
- 基础数据服务(药品主数据)
- 库存服务(实时库存管理)
- 处方服务(医嘱处理)
- 报表服务(数据分析)
采用Nacos作为注册中心,通过Feign实现服务间调用。特别要注意药品编码的全局唯一性,我们采用"分类码(4位)+剂型码(2位)+序列码(6位)"的12位编码规则。
3. 核心功能实现
3.1 智能库存管理
java复制// 库存扣减的分布式事务处理
@Transactional
public boolean reduceStock(String medicineCode, int amount) {
// 1. 检查库存余量
MedicineStock stock = stockMapper.selectById(medicineCode);
if(stock.getCurrentStock() < amount) {
throw new BusinessException("库存不足");
}
// 2. 记录操作日志
stockLogMapper.insert(new StockLog(medicineCode, -amount));
// 3. 更新库存
stockMapper.reduceStock(medicineCode, amount);
// 4. 触发预警检查
if(stock.getCurrentStock() - amount < stock.getMinStock()) {
rabbitTemplate.convertAndSend("stock.alert", medicineCode);
}
return true;
}
关键点:采用"先查后改+日志记录"模式,配合RabbitMQ实现异步预警,避免长事务问题
3.2 药品效期三级预警
建立效期管理矩阵:
| 预警级别 | 剩余天数 | 处理措施 |
|---|---|---|
| 一级 | ≤30天 | 界面红标+短信通知 |
| 二级 | 31-60天 | 界面黄标+系统消息 |
| 三级 | 61-90天 | 界面蓝标提示 |
通过Spring Scheduled实现每日凌晨效期扫描:
java复制@Scheduled(cron = "0 0 3 * * ?")
public void checkExpiration() {
List<Medicine> expiringList = medicineMapper.selectExpiringMedicines();
expiringList.forEach(med -> {
int remainDays = ChronoUnit.DAYS.between(LocalDate.now(), med.getExpireDate());
// 根据remainDays触发不同级别预警
});
}
4. 处方审核模块设计
4.1 药品冲突规则引擎
采用Drools规则引擎实现7类审核规则:
- 配伍禁忌(如头孢+酒精)
- 剂量超标(根据体重计算)
- 重复用药
- 特殊人群禁忌(孕妇/儿童)
- 过敏史拦截
- 医保限制
- 库存检查
规则示例:
drl复制rule "抗生素与酒精冲突"
when
$p : Prescription(medicineCode == "J0101")
$a : Prescription(medicineCode == "Y0025")
then
throw new ConflictException("头孢类与酒精存在配伍禁忌");
end
4.2 审核流程优化
原始串行审核耗时约2-3秒/处方,通过以下优化降至300-500ms:
- 并行检查:使用CompletableFuture实现规则并行执行
- 缓存预热:将药品冲突关系提前加载到Redis
- 结果复用:对相同医生开立的相似处方进行结果缓存
5. 高并发场景应对
5.1 库存热点问题解决方案
采用三级缓存架构:
- JVM缓存(Caffeine):存储科室常用药品
- Redis集群:存储全院药品实时库存
- 数据库分库:按药品类别分库(西药库/中药库/耗材库)
库存扣减采用CAS乐观锁:
sql复制UPDATE medicine_stock
SET current_stock = current_stock - #{amount}
WHERE medicine_code = #{code} AND current_stock >= #{amount}
5.2 分布式事务处理
采购入库时采用TCC模式:
- Try阶段:预占库存额度
- Confirm阶段:实际入库
- Cancel阶段:释放预占额度
通过Seata实现全局事务管理,异常场景下能保证数据一致性。
6. 安全与合规设计
6.1 权限控制矩阵
基于RBAC模型设计5级权限:
- 药库管理员(全权限)
- 药房药师(出入库管理)
- 门诊医生(处方开具)
- 护士(药品领取)
- 财务(报表查看)
采用Spring Security + JWT实现,关键接口添加@PreAuthorize注解:
java复制@PreAuthorize("hasRole('PHARMACIST') || hasRole('ADMIN')")
@PostMapping("/stock/in")
public Result stockIn(@RequestBody StockInDTO dto) {
// 入库逻辑
}
6.2 审计日志设计
所有关键操作记录审计日志,包含:
- 操作时间
- 操作人
- IP地址
- 请求参数
- 修改前后的值(通过MyBatis拦截器实现)
日志存储采用ES集群,保留周期为5年,符合医疗行业监管要求。
7. 性能优化实战
7.1 药品查询加速
对200万条药品数据采用以下优化手段:
- 建立组合索引:
INDEX(classification, name, specification) - 引入Elasticsearch实现模糊搜索
- 查询结果分页缓存(Redis)
查询响应时间从1200ms降至200ms以内。
7.2 大批量数据处理
药品盘点时采用分批处理策略:
java复制public void batchUpdateStock(List<StockDTO> list) {
int batchSize = 1000;
Lists.partition(list, batchSize).forEach(batch -> {
stockMapper.batchUpdate(batch); // 使用MyBatis的foreach标签
});
}
配合JDBC批处理参数:
yaml复制spring:
datasource:
hikari:
data-source-properties:
rewriteBatchedStatements: true
8. 部署与监控
8.1 容器化部署
采用Docker Compose编排:
yaml复制version: '3'
services:
data-service:
image: hospital/medicine-data:v1.2
ports:
- "8081:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
deploy:
resources:
limits:
cpus: '2'
memory: 2G
8.2 监控体系搭建
- Prometheus采集JVM指标
- Grafana展示关键仪表盘
- ELK收集业务日志
- 自定义健康检查接口:
java复制@GetMapping("/health")
public Map<String, Object> healthCheck() {
return Map.of(
"dbStatus", checkDatabase(),
"redisStatus", checkRedis(),
"mqStatus", checkRabbitMQ()
);
}
9. 踩坑经验分享
- 药品编码冲突:初期采用自增ID导致多院区同步时冲突,后改用分类编码方案
- 库存超卖问题:未考虑分布式锁导致,最终采用Redis+Lua脚本实现原子操作
- 效期计算误差:直接使用new Date()获取时间存在时区问题,改为LocalDate解决
- Drools规则加载:规则变更后需要手动调用KieContainer.updateToVersion
特别提醒:药品管理系统必须通过等保三级认证,开发过程中就要考虑日志审计、数据加密等安全要求,后期补充成本极高。我们在二期改造中为此多投入了2个月工作量。