数据库设计
本章节详细介绍 MootingBackend 的数据库表结构设计。
数据库信息
| 属性 | 值 |
|---|---|
| 数据库类型 | SQL Server 2022 |
| 数据库名称 | user_system |
| 字符集 | UTF-8 (NVARCHAR) |
| 时间类型 | DATETIMEOFFSET (带时区) |
实体关系图
┌─────────────────────┐
│ User │
│ (user_id: PK) │
└─────────┬───────────┘
│
│ 1:N
│
┌─────┴─────┬─────────────────┬─────────────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│UserDevice│ │Transcription│ │Transcription│ │UserBehavior │
│ (sn:PK) │ │ Record │ │ Usage │ │ Event │
└─────────┘ └─────────────┘ └─────────────┘ └─────────────┘表结构详解
1. user (用户表)
存储用户账号基本信息。
sql
CREATE TABLE [user] (
user_id BIGINT IDENTITY(1,1) PRIMARY KEY,
phone VARCHAR(20) UNIQUE,
email VARCHAR(128) UNIQUE,
password_hash VARCHAR(255),
created_at DATETIMEOFFSET NOT NULL,
updated_at DATETIMEOFFSET
);| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| user_id | BIGINT | PK, Auto | 用户唯一标识 |
| phone | VARCHAR(20) | UNIQUE, NULL | 手机号 |
| VARCHAR(128) | UNIQUE, NULL | 邮箱地址 | |
| password_hash | VARCHAR(255) | NULL | BCrypt 加密密码 |
| created_at | DATETIMEOFFSET | NOT NULL | 创建时间 |
| updated_at | DATETIMEOFFSET | NULL | 更新时间 |
设计说明
- phone 和 email 至少有一个非空
- password_hash 可为空(验证码登录不需要密码)
- 使用 DATETIMEOFFSET 存储带时区的时间戳
2. user_device (设备表)
存储用户绑定的设备信息。
sql
CREATE TABLE user_device (
sn VARCHAR(64) PRIMARY KEY,
user_id BIGINT NOT NULL,
mac VARCHAR(32) NOT NULL,
product_model VARCHAR(64) NOT NULL,
created_at DATETIMEOFFSET NOT NULL
);
CREATE INDEX idx_user_device_user_id ON user_device(user_id);| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| sn | VARCHAR(64) | PK | 设备序列号 |
| user_id | BIGINT | NOT NULL | 所属用户 ID |
| mac | VARCHAR(32) | NOT NULL | MAC 地址 |
| product_model | VARCHAR(64) | NOT NULL | 产品型号 |
| created_at | DATETIMEOFFSET | NOT NULL | 绑定时间 |
业务规则
- 一个用户可绑定多个设备
- 设备序列号 (SN) 全局唯一
- 设备只能绑定给一个用户
3. transcription_record (转写记录表)
存储语音转写的完整记录。
sql
CREATE TABLE transcription_record (
transcription_record_id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT NOT NULL,
record_title VARCHAR(32),
text NVARCHAR(MAX),
text_length BIGINT,
language VARCHAR(32),
duration_seconds INT,
created_at DATETIMEOFFSET NOT NULL,
updated_at DATETIMEOFFSET
);
CREATE INDEX idx_transcription_record_user_id ON transcription_record(user_id);| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| transcription_record_id | BIGINT | PK, Auto | 记录 ID |
| user_id | BIGINT | NOT NULL | 所属用户 ID |
| record_title | VARCHAR(32) | NULL | 记录标题 |
| text | NVARCHAR(MAX) | NULL | 转写文本 |
| text_length | BIGINT | NULL | 文本字符数 |
| language | VARCHAR(32) | NULL | 语言代码 |
| duration_seconds | INT | NULL | 音频时长 (秒) |
| created_at | DATETIMEOFFSET | NOT NULL | 创建时间 |
| updated_at | DATETIMEOFFSET | NULL | 更新时间 |
字段说明
text使用 NVARCHAR(MAX) 支持 Unicode 和大文本language使用标准语言代码,如zh-CN,en-UStext_length在插入时自动计算
4. transcription_usage (使用量统计表)
记录用户的转写使用量统计。
sql
CREATE TABLE transcription_usage (
transcription_usage_id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT NOT NULL,
date VARCHAR(10),
total_usage BIGINT,
daily_usage BIGINT,
created_at DATETIMEOFFSET NOT NULL
);
CREATE INDEX idx_transcription_usage_user_id ON transcription_usage(user_id);| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| transcription_usage_id | BIGINT | PK, Auto | 记录 ID |
| user_id | BIGINT | NOT NULL | 所属用户 ID |
| date | VARCHAR(10) | NULL | 日期 (yyyy-MM-dd) |
| total_usage | BIGINT | NULL | 累计使用秒数 |
| daily_usage | BIGINT | NULL | 当日使用秒数 |
| created_at | DATETIMEOFFSET | NOT NULL | 创建时间 |
设计模式
每个用户有多行记录:
- 累计行:
date = NULL,total_usage= 总秒数 - 每日行:
date = '2026-01-29',daily_usage= 当日秒数
5. user_behavior_event (行为事件表)
存储用户行为事件用于分析。
sql
CREATE TABLE user_behavior_event (
user_behavior_event_id BIGINT IDENTITY(1,1) PRIMARY KEY,
user_id BIGINT NOT NULL,
event_type VARCHAR(32) NOT NULL,
event_value VARCHAR(32),
location VARCHAR(128),
created_at DATETIMEOFFSET NOT NULL
);
CREATE INDEX idx_user_behavior_event_user_id ON user_behavior_event(user_id);
CREATE INDEX idx_user_behavior_event_type ON user_behavior_event(event_type);| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| user_behavior_event_id | BIGINT | PK, Auto | 事件 ID |
| user_id | BIGINT | NOT NULL | 所属用户 ID |
| event_type | VARCHAR(32) | NOT NULL | 事件类型 |
| event_value | VARCHAR(32) | NULL | 事件值 |
| location | VARCHAR(128) | NULL | 位置信息 |
| created_at | DATETIMEOFFSET | NOT NULL | 事件时间 |
支持的事件类型:
| event_type | 说明 | event_value 示例 |
|---|---|---|
login | 登录事件 | NULL |
translation_on | 翻译开关 | true / false |
voice_provider | 语音服务商 | tencent / iflytek |
language_choice | 语言选择 | zh-CN / en-US |
ambient_sound | 环境音检测 | enabled / disabled |
subtitle_layout | 字幕布局 | top / bottom |
volume_detection | 音量检测 | auto / manual |
JPA 实体映射
User 实体
java
@Entity
@Table(name = "user")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long userId;
@Column(unique = true)
private String phone;
@Column(unique = true)
private String email;
@Column(name = "password_hash")
private String passwordHash;
@Column(name = "created_at", nullable = false)
private Instant createdAt;
@Column(name = "updated_at")
private Instant updatedAt;
@PrePersist
protected void onCreate() {
createdAt = Instant.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = Instant.now();
}
}数据迁移
JPA 配置为 ddl-auto=update,启动时自动同步表结构。
生产环境
生产环境应使用 Flyway 或 Liquibase 进行版本化数据库迁移,避免使用 ddl-auto。