在设计站内信系统时,需要考虑消息的存储、用户状态的管理(未读、已读)、消息推送、定时清理等。以下是站内信消息未读/已读数据表设计的思路与方案,以及如何用Golang实现的简要介绍。
数据表设计思路
- 消息表(messages): 存储所有站内信的内容。一个消息可能会发送给多个用户,因此我们把站内信的内容与接收者的状态分开管理。
id: 消息的唯一标识(主键)sender_id: 发送者用户IDtitle: 消息标题content: 消息内容create_time: 消息发送时间type: 消息类型(系统通知、用户消息等)
CREATE TABLE messages (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
sender_id BIGINT NOT NULL,
title VARCHAR(255),
content TEXT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
type INT
);
- 用户-消息关联表(user_message_status): 用于存储每个用户对消息的状态(未读、已读、删除等)。
id: 唯一标识(主键)user_id: 接收消息的用户IDmessage_id: 消息ID(关联messages表)status: 消息状态(0:未读,1:已读,2:删除等)read_time: 阅读时间(如果已读则记录阅读时间)
CREATE TABLE user_message_status (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
message_id BIGINT NOT NULL,
status TINYINT DEFAULT 0, -- 0未读,1已读,2删除
read_time TIMESTAMP NULL,
CONSTRAINT fk_message FOREIGN KEY (message_id) REFERENCES messages(id),
CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id)
);
站内信基本流程
- 发送消息:将消息插入
messages表,并根据接收用户列表在user_message_status中为每个用户创建一条记录,默认状态为未读。 - 读取消息:用户读取消息时,更新
user_message_status中的status为已读,并记录read_time。 - 查询未读消息:根据用户ID查询
user_message_status表中status为未读的消息。 - 删除消息:可将
status更新为删除,或者直接从数据库中移除该条数据。
用Golang实现
使用Golang实现该方案可以结合数据库驱动(如GORM、database/sql等)和常用的Web框架(如Gin或Echo)。
1. 初始化数据库模型(使用GORM为例)
import (
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 消息结构体
type Message struct {
ID uint `gorm:"primaryKey"`
SenderID uint
Title string
Content string
CreateTime time.Time `gorm:"autoCreateTime"`
Type int
}
// 用户-消息状态结构体
type UserMessageStatus struct {
ID uint `gorm:"primaryKey"`
UserID uint
MessageID uint
Status int // 0未读,1已读,2删除
ReadTime time.Time
}
// 初始化数据库连接
func InitDB() (*gorm.DB, error) {
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
db.AutoMigrate(&Message{}, &UserMessageStatus{})
return db, nil
}
2. 发送消息
func SendMessage(db *gorm.DB, senderID uint, title, content string, userIDs []uint) error {
// 插入消息
message := Message{
SenderID: senderID,
Title: title,
Content: content,
Type: 1, // 假设1是用户消息类型
}
if err := db.Create(&message).Error; err != nil {
return err
}
// 为每个接收者创建未读记录
for _, userID := range userIDs {
status := UserMessageStatus{
UserID: userID,
MessageID: message.ID,
Status: 0, // 未读
}
db.Create(&status)
}
return nil
}
3. 阅读消息
func MarkMessageAsRead(db *gorm.DB, userID, messageID uint) error {
// 更新为已读
return db.Model(&UserMessageStatus{}).Where("user_id = ? AND message_id = ?", userID, messageID).
Updates(map[string]interface{}{
"status": 1, // 已读
"read_time": time.Now(),
}).Error
}
4. 获取未读消息
func GetUnreadMessages(db *gorm.DB, userID uint) ([]Message, error) {
var messages []Message
db.Joins("JOIN user_message_status ON messages.id = user_message_status.message_id").
Where("user_message_status.user_id = ? AND user_message_status.status = 0", userID).
Find(&messages)
return messages, nil
}
总结
- 通过数据库表的设计,消息和用户状态分离,保证了扩展性和可维护性。
- 使用
GORM等ORM工具可以方便地操作数据库,配合Golang中的业务逻辑实现站内信的功能,包括发送、读取、未读查询等。