小程序(十六)消息功能
创始人
2025-06-01 21:05:09

文章目录

  • 一、数据库设计
  • 二、系统消息的发送与收取设计
  • 三、业务设计
  • 四、消息实体设计
  • 五、SpringBoot异步任务
    • 1、开启异步注解功能
    • 2、线程池创建
    • 3、异步任务——消息生产
    • 4、同步任务——消息消费(写入MySQL)


一、数据库设计

很多人以为消息模块的数据表设计起来很简单,创建一个 消息表 就可以存储系统消息了,我只
能说,你把问题想简单了。
公告消息记录应该全局唯一,还是为每个用户创建一条公告消息?
这个问题取决于你是怎么理解系统消息的,如果你不希望系统记录用户是否阅读了某条消息,哪
些消息是未读消息,那么一个公告消息在数据表中就是一条唯一的记录,存储起来非常节省空
间。但是很少有系统会这么设计,如果系统消息很多,又不告诉用户哪些是已读消息,哪些是未
读消息,造成用户体验非常不好。所以系统必须要记录下来,用户阅读了哪些消息,还有哪些消
息是未读的。
如果一个电商系统有800万注册用户,那么系统发出一条公告消息之后,意味着要在消息表中插
入800万条消息记录,每条记录是发给某位用户的公告消息。瞬间数据库的负载达到顶峰,数据
库被大量的写入操作占用,导致电商系统正常的业务无法展开。请记住,一条公告消息就能让电
商系统濒临崩溃。微信有11亿的日活用户,如果微信给所有用户发出一条公告消息,岂不是微信
的服务器就挂了?看来消息模块的数据库架构确实有技术含量。

二、系统消息的发送与收取设计

在这里插入图片描述

三、业务设计

用户登陆系统的时候,后端系统要创建异步线程,接收消息队列MQ中的消息,然后把消息写到数据库里面。
在这里插入图片描述

四、消息实体设计

@Data
public class MessageEntity implements Serializable {private String uuid; //UUID UUID值,并且设置有唯一性索引,防止消息被重复消费private String senderId; // Integer 发送者ID,就是用户ID。如果是系统自动发出,这个ID值是0private String senderPhoto; // String 发送者的头像URL。在消息页面要显示发送人的头像private String senderName; // String 发送者名称,也就是用户姓名。在消息页面要显示发送人的名字private String msg; // String 消息正文private Date sendTime; // Date 发送时间
}
@Data
public class MessageRef implements Serializable {private String messageId;// UUID message记录的_idprivate Integer receiverId;// String 接收人ID
}

五、SpringBoot异步任务

1、开启异步注解功能

@SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
@EnableAsync  //开启异步注解功能
public class WeChatSkApplication {public static void main(String[] args) {SpringApplication.run(WeChatSkApplication.class, args);}}

2、线程池创建

默认情况下,spring会为我们的异步方法创建一个线程去执行,如果该方法被调用次数非常多的话,需要创建大量的线程,会导致资源浪费。

这时,我们可以定义一个线程池,异步方法将会被自动提交到线程池中执行。

@Configuration
public class ThreadPoolConfig {@Value("${thread.pool.corePoolSize:5}")private int corePoolSize;@Value("${thread.pool.maxPoolSize:10}")private int maxPoolSize;@Value("${thread.pool.queueCapacity:200}")private int queueCapacity;@Value("${thread.pool.keepAliveSeconds:30}")private int keepAliveSeconds;@Value("${thread.pool.threadNamePrefix:ASYNC_}")private String threadNamePrefix;@Beanpublic Executor MessageExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);executor.setThreadNamePrefix(threadNamePrefix);executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}
}

3、异步任务——消息生产

@Service
public class AsyncService {@Autowiredprivate MessageTask messageTask;@Autowiredprivate RoleMapper roleMapper;@Autowiredprivate MessageMapper mapper;@Asyncpublic void sendMessageToMQ(MessageEntity messageEntity) {//1、消息插入数据库消息表mapper.insert(messageEntity);Integer messageid = messageEntity.getId();//2、查询角色对应的用户IDList userIds = roleMapper.selectUserIdByRoleId(messageEntity.getRoleId());userIds.forEach(uid->{MessageRef messageRef = new MessageRef();messageRef.setMessageId(messageid);messageRef.setReceiverId(uid);//3、将所有接收人的MessageRef异步写入MQmessageTask.sendAsync("topicName"+uid,messageRef);});}
}

4、同步任务——消息消费(写入MySQL)

相关内容

热门资讯

洛博特卡:决赛只有赢家会被记住... 在意超杯决赛即将到来之际,那不勒斯中场洛博特卡接受了慢镜头的采访,他的话语引发了广泛关注。"人们只记...
原创 中... 这是两国去美元化的硬核联动。 俄罗斯海关数据显示,中国连续两月创纪录地购买俄罗斯黄金,今年11月花9...
原创 突... 12月22日,A股市场被一片红色席卷——海南自贸港板块整体暴涨超9%,神农种业、康芝药业20%涨停,...
500枚比特币,黑客盗走490... 在加密货币这个充满传奇与风险的“暗黑森林”里,每天都在上演着令人瞠目结舌的剧目。有的人因一夕暴富而登...
纪委回应退休职工举报南博前院长 近日,“南京博物院馆藏明代仇英《江南春》图卷现身拍卖市场”,持续引发关注。12月21日,一名自称为南...