数据库落地执行指南
目标
本文档用于把 docs/数据库 下的表设计真正落到本地 MySQL 中,并给出建表后的检查 SQL。
当前项目默认数据库配置来自 conf/app.ini:
ini
[mysql]
host = 127.0.0.1
port = 3306
username = root
password = admin
database = flow_talk
parse_time = true执行前置
确认本地 MySQL 已启动,并可以使用项目配置连接:
bash
mysql -h 127.0.0.1 -P 3306 -u root -p创建数据库:
sql
CREATE DATABASE IF NOT EXISTS flow_talk
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_unicode_ci;
USE flow_talk;建表顺序
必须按依赖顺序执行:
- 数据库表创建-人员:创建
users - 数据库表创建-会话:创建
conversations、conversation_members - 数据库表创建-消息:创建
messages - 数据库表创建-设备:创建
user_devices - 数据库表创建-消息回执:创建
message_receipts
一次性建表后的总检查
执行完所有建表 SQL 后,检查表是否存在:
sql
SHOW TABLES;预期至少包含:
text
users
conversations
conversation_members
messages
user_devices
message_receipts检查表结构:
sql
DESC users;
DESC conversations;
DESC conversation_members;
DESC messages;
DESC user_devices;
DESC message_receipts;检查关键索引:
sql
SHOW INDEX FROM users;
SHOW INDEX FROM conversations;
SHOW INDEX FROM conversation_members;
SHOW INDEX FROM messages;
SHOW INDEX FROM user_devices;
SHOW INDEX FROM message_receipts;最小数据验证
以下 SQL 用于验证关键唯一约束和关系字段是否能支撑后续代码实现。
插入两个本地用户:
服务端不对本地用户密码做加密或哈希;通过注册接口创建用户时,密码同样会以明文写入 users.password:
sql
INSERT INTO users (username, password, nickname, auth_source, status)
VALUES
('alice', '123456', 'Alice', 'local', 1),
('bob', '123456', 'Bob', 'local', 1);创建单聊会话:
sql
INSERT INTO conversations (type, direct_key)
VALUES ('direct', '1:2');
INSERT INTO conversation_members (conversation_id, user_id, role, status)
VALUES
(1, 1, 'member', 'active'),
(1, 2, 'member', 'active');插入一条文本消息,并更新会话最后消息:
sql
INSERT INTO messages (conversation_id, sender_id, client_msg_id, message_type, content)
VALUES (1, 1, 'client-001', 'text', JSON_OBJECT('text', 'hello'));
UPDATE conversations
SET last_message_id = 1, last_message_at = NOW()
WHERE id = 1;标记用户 2 已读:
sql
UPDATE conversation_members
SET last_read_message_id = 1, last_read_at = NOW()
WHERE conversation_id = 1 AND user_id = 2;上报设备:
sql
INSERT INTO user_devices (user_id, data)
VALUES (1, JSON_OBJECT('platform', 'web', 'device_id', 'web-001'));写入消息回执:
sql
INSERT INTO message_receipts (message_id, user_id, status)
VALUES (1, 2, 'read');常见约束验证
验证用户名唯一:
sql
INSERT INTO users (username, password, nickname, auth_source, status)
VALUES ('alice', '123456', 'Alice2', 'local', 1);预期结果:失败,命中 uk_users_username。
验证单聊唯一:
sql
INSERT INTO conversations (type, direct_key)
VALUES ('direct', '1:2');预期结果:失败,命中 uk_conversations_direct_key。
验证会话成员唯一:
sql
INSERT INTO conversation_members (conversation_id, user_id, role, status)
VALUES (1, 1, 'member', 'active');预期结果:失败,命中 uk_conversation_members_conversation_user。
验证消息幂等唯一:
sql
INSERT INTO messages (conversation_id, sender_id, client_msg_id, message_type, content)
VALUES (1, 1, 'client-001', 'text', JSON_OBJECT('text', 'hello again'));预期结果:失败,命中 uk_messages_sender_client_msg。
与代码实现的关系
当前 SQL 不声明数据库外键,因此代码实现必须负责以下校验:
- 写入
conversation_members前确认users.id和conversations.id存在 - 写入
messages前确认发送者是会话 active 成员 - 更新已读游标前确认消息属于当前会话
- 写入
user_devices前确认请求体user_id来自当前登录态 - 写入
message_receipts前确认消息和接收用户有效
这些校验应放在 models 层,controller 只负责参数绑定、当前用户读取和 HTTP 响应转换。