在我的由 MySQL 数据库支持的 Web 应用程序中,我想提供一个消息传递系统,其中消息被分组到多个用户之间的对话中,但我坚持设计一个满足我的一些需求的表结构:
- 多个用户可以参与一个对话
- 用户可以加入、阅读、离开和删除对话
- 收件箱视图应该生成尽可能少的查询
现在,可以通过使用联结表来解决多对多关系的第一个要求。但事实证明,在为收件箱视图编写选择查询时会产生很多问题。
第二个要求也被证明是一个挑战。如果用户离开对话,他应该仍然可以阅读旧消息。对话中剩余用户之间的新消息不应与离开的用户共享。我首先考虑使用树状结构进行对话。每次用户加入或离开对话时,都会创建一个引用父对话的新对话,并创建与联结表中剩余参与者的新关系。
第三个要求似乎也不是微不足道的。收件箱视图应显示与特定用户作为参与者的对话列表。此外,应为每个对话显示附加信息:所有当前参与者的姓名、对话的最后回复以及回复的作者。将收件箱视图视为包含有关它们所属对话的附加信息的消息列表。
我目前的方法如下所示:
CREATE TABLE `conversation` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parentId` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `parentId` (`parentId`),
CONSTRAINT `conversation_ibfk_1` FOREIGN KEY (`parentId`) REFERENCES `conversation` (`id`)
);
CREATE TABLE `participant` (
`userId` int(11) unsigned NOT NULL,
`conversationId` int(11) unsigned NOT NULL,
`readAt` datetime DEFAULT NULL,
PRIMARY KEY (`userId`,`conversationId`),
KEY `conversationId` (`conversationId`),
CONSTRAINT `participant_ibfk_2` FOREIGN KEY (`conversationId`) REFERENCES `conversation` (`id`),
CONSTRAINT `participant_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `user` (`id`)
);
CREATE TABLE `reply` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`conversationId` int(11) unsigned NOT NULL,
`userId` int(11) unsigned NOT NULL,
`text` text NOT NULL,
PRIMARY KEY (`id`),
KEY `conversationId` (`conversationId`),
KEY `userId` (`userId`),
CONSTRAINT `reply_ibfk_2` FOREIGN KEY (`userId`) REFERENCES `user` (`id`),
CONSTRAINT `reply_ibfk_1` FOREIGN KEY (`conversationId`) REFERENCES `conversation` (`id`)
);
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
);
我在这里碰壁了,找不到满足我所有需求的解决方案。也许这里有人可以就如何处理这种数据库设计给我一些建议。