智慧社区系统从 0 到 1多端复用架构与抢单池并发控制实战智慧社区系统本质上是一套「后端统一 多端复用 本地生活服务履约」的业务中台。它把跑腿代取、家政上门、家电清洗维修、上门洗车、衣鞋洗护、本地商城、优惠券导购、小时工预约这些分散的社区服务收敛到同一套用户、订单、商家和结算模型里再通过小程序、公众号、H5 和 APP 触达居民。落到技术实现上比较常见且容易维护的组合是后端 Spring Boot MyBatis Plus MySQL用户端用 UniAppVue 语法一套代码多端编译管理后台用 Vue Element UI。下面按模块建模、架构分层、并发控制、多端鉴权与部署五个部分展开。一、业务边界与数据建模先把智慧社区的功能拆成四个域避免后期表结构反复推翻用户域预约地址簿、我的快递查询、订单分类、邀请好友、会员状态、积分签到、历史浏览。服务域跑腿服务、家政服务、上门服务、小时工、家电清洗、家电维修、上门洗车、衣鞋洗护。交易域商城、淘客优惠券、本地生活团购、订单支付与退款。管理域商家中心、个人资料修改、账号注销、投诉处理、抢单池调度。其中「抢单池」是跑腿与家政类业务的调度核心建议单独建表与业务订单表解耦CREATETABLEgrab_pool(idBIGINTNOTNULLAUTO_INCREMENT,order_idBIGINTNOTNULLCOMMENT业务订单ID,service_typeTINYINTNOTNULLCOMMENT服务类型:1跑腿 2家政 3维修,statusTINYINTNOTNULLDEFAULT0COMMENT0待抢 1已抢 2已取消,taker_idBIGINTNULLCOMMENT接单服务者ID,grab_timeDATETIMENULL,versionINTNOTNULLDEFAULT0COMMENT乐观锁版本,create_timeDATETIMENOTNULLDEFAULTCURRENT_TIMESTAMP,PRIMARYKEY(id),UNIQUEKEYuk_order(order_id),KEYidx_status_type(status,service_type))ENGINEInnoDBDEFAULTCHARSETutf8mb4;注意uk_order索引它是防止同一订单重复入池的后一道防线比在应用层做判断可靠得多。二、架构分层与多端复用后端按标准三层组织MyBatis Plus 负责单表 CRUD复杂统计走 XML 或手写 SQLcommunity-service ├── community-api # 对外接口层Controller DTO ├── community-service # 业务逻辑层事务边界在这一层 ├── community-mapper # MyBatis Plus Mapper ├── community-domain # 实体与枚举 └── community-common # 统一返回、异常、工具类用户端用 UniApp 的核心收益是一套业务代码编译到四个端。但不同端的差异必须提前隔离否则会在页面里堆满if。推荐用条件编译// utils/pay.jsexportfunctionpay(orderNo,amount){// #ifdef MP-WEIXINreturnPay(orderNo)// 小程序.requestPayment// #endif// #ifdef H5returnh5Pay(orderNo,amount)// H5收银台// #endif// #ifdef APP-PLUSreturnappPay(orderNo)// APPplus.payment// #endif}同理登录、分享、订阅消息、定位权限这四类能力都收敛到utils/下的统一适配层页面只调用统一方法。这样新增一个端时改动量集中在一个目录而不是全站搜替换。三、抢单池的并发控制与订单状态机抢单是智慧社区里典型的并发场景一个订单推送后多个服务者同时点击接单。常见做法有三种按可靠性递增数据库乐观锁UPDATE grab_pool SET status1, taker_id? WHERE id? AND status0靠affected rows判断是否抢到。实现简单适合并发量不高的社区场景。Redis 分布式锁SET lock:order:{id} {uuid} NX PX 3000抢到锁后再更新数据库注意锁的续期与释放要用 Lua 保证原子性。队列串行化把抢单请求投递到 MQ 或 Redis List单消费者顺序处理天然避免竞争。生产环境建议乐观锁兜底 Redis 锁削峰组合使用publicbooleangrab(LongorderId,LongtakerId){Stringkeylock:grab:orderId;StringtokenUUID.randomUUID().toString();BooleanlockedredisTemplate.opsForValue().setIfAbsent(key,token,Duration.ofSeconds(3));if(Boolean.FALSE.equals(locked)){thrownewBizException(当前订单正被其他服务者接单);}try{introwsgrabPoolMapper.grab(orderId,takerId);if(rows0){thrownewBizException(订单已被抢走);}orderService.transferToTaker(orderId,takerId);returntrue;}finally{// Lua 脚本比对 token 后删除避免误删他人锁redisTemplate.execute(DEL_IF_EQUALS_SCRIPT,Collections.singletonList(key),token);}}对应 MapperUpdate(UPDATE grab_pool SET status1, taker_id#{takerId}, grab_timeNOW(), versionversion1 WHERE id#{orderId} AND status0)intgrab(Param(orderId)LongorderId,Param(takerId)LongtakerId);订单状态建议用枚举 状态机约束禁止在业务代码里随意setStatuspublicenumOrderStatus{CREATED,// 待支付PAID,// 已支付待派单GRABBED,// 已接单SERVING,// 服务中FINISHED,// 已完成CANCELED;// 已取消}同时在order表加(user_id, status)和(taker_id, status)两个联合索引因为「订单分类」和「历史浏览」几乎都按这两个维度查询。四、多端鉴权与消息触达智慧社区要同时面对小程序、公众号、H5 和 APP鉴权方案要统一。推荐双 Token 模式业务 TokenJWT承载userId、role居民 / 服务者 / 商家有效期较短。刷新 Token存 Redis绑定设备指纹支持主动踢下线。第三方平台的openid与站内userId通过user_third表关联一个用户可绑定多个端CREATETABLEuser_third(idBIGINTNOTNULLAUTO_INCREMENT,user_idBIGINTNOTNULL,platformVARCHAR(20)NOTNULLCOMMENTMP/MP_OA/H5/APP,open_idVARCHAR(64)NOTNULL,PRIMARYKEY(id),UNIQUEKEYuk_platform_open(platform,open_id))ENGINEInnoDBDEFAULTCHARSETutf8mb4;消息触达方面小程序用订阅消息、公众号用模板消息、APP 用厂商推送同样封装成notifyService.send(userId, templateCode, params)内部按端路由。订单超时未支付、接单后超时未上门这类场景用延时队列RocketMQ 延时消息或 Redisson 的RDelayedQueue比纯定时任务轮询更准。五、部署与二次开发的注意点部署上没什么玄学关键是把配置外置spring:datasource:url:jdbc:mysql://${DB_HOST}:3306/community?useUnicodetrueserverTimezoneAsia/Shanghaiusername:${DB_USER}password:${DB_PWD}redis:host:${REDIS_HOST}前端产物分两套管理后台npm run build出静态文件交给 NginxUniApp 按端分别打包小程序走开发者工具上传H5 与后台共用一个 Nginx 实例的不同 location 即可注意 H5 的 history 路由要配try_files $uri $uri/ /index.html。如果是在既有智慧社区系统上做二次开发建议优先关注四点一是确认订单状态机的流转入口是否二是检查抢单相关逻辑是否只走数据库条件更新三是把支付回调的幂等处理补齐四是理清定时任务在集群下的重复执行问题用分布式锁或调度平台。这四点理顺了后续加同城遛狗、同城搭子社交这类新场景时基本可以复用现有的用户、订单和消息体系。FAQQ1智慧社区后端为什么常用 Spring Boot MyBatis Plus MySQLSpring Boot 的生态能直接对接、支付、短信等 SDKMyBatis Plus 在单表 CRUD 和分页上开发效率高复杂 SQL 又能随时下沉到 XMLMySQL 在社区级数据量下足够稳定配合索引优化可支撑订单与抢单池的高频读写。Q2一套 UniApp 代码真的能覆盖小程序、公众号、H5 和 APP 吗业务页面和请求层可以完全复用差异集中在登录、支付、分享、推送、定位这五类平台能力上用条件编译隔离到独立模块即可。需要注意各端审核与权限要求不同上线前要分别验证。Q3抢单池高并发下怎样避免一单多抢三道防线数据库索引阻止重复入池、WHERE status0的条件更新保证只有一次成功、Redis 分布式锁做前置削峰。三者叠加后即使出现短时并发也不会产生重复接单。Q4订单超时未支付或超时未服务怎么处理优先用延时消息在到期时触发取消或提醒若基础设施不具备可用定时任务扫描加分布式锁防重复执行同时保证取消操作本身幂等。Q5二次开发时容易踩的坑是什么状态字段被绕过状态机直接修改导致后续流转异常支付回调未做幂等重复入账集群环境下定时任务重复执行。建议在改动前先画出完整的状态流转图和任务清单。