很多人以为消息模块的数据表设计起来很简单,创建一个 消息表 就可以存储系统消息了,我只
能说,你把问题想简单了。
公告消息记录应该全局唯一,还是为每个用户创建一条公告消息?
这个问题取决于你是怎么理解系统消息的,如果你不希望系统记录用户是否阅读了某条消息,哪
些消息是未读消息,那么一个公告消息在数据表中就是一条唯一的记录,存储起来非常节省空
间。但是很少有系统会这么设计,如果系统消息很多,又不告诉用户哪些是已读消息,哪些是未
读消息,造成用户体验非常不好。所以系统必须要记录下来,用户阅读了哪些消息,还有哪些消
息是未读的。
如果一个电商系统有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
}
@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);}}
默认情况下,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;}
}
@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);});}
}
上一篇:阿里妈妈智能诊断工程能力建设