2.3-db.md
2.3 数据库设计¶
2.3.1 mysql 数据库版本概述¶
一个新开发的程序,需要有数据库的配合。MySQL 是一种关系数据库管理系统,它最明显的机制就是将有关联的数据各个建表,多个表格通过不同的 MySQL 语句实现对数据的增删改查,几个表格在一起相辅相成,分工明确。整体条理清晰,加快了速度并且提高了灵活性。
这里使用 MySQL 数据库的版本为 "mysql": "^2.18.1",实现基本的增删改查。目前不考虑数据库性能、高并发查询等问题。
2.3.2 mysql 数据库结构设计¶
本地需要新建数据库 novel
在数据库中,新建数据库表:
1-用户表 user
2-书籍表 book
3-评论表 comment
4-用户书籍表 user_book: 用户表和书籍表,是多对多的关系。一个用户可以拥有多本书,一本书也可以被多个用户下载。所以需要一个中间表 user-book 存放外键。
TODO:不同表结构的关系分析
用户表和评论表,是一对多的关系。一个用户可以拥有多个评论。
评论表和书籍表,是一对多的关系。一本书可有拥有多条评论。
那么评论表中需要有用户表的外键,书籍表的外键。
删除用户,需要删除对应 user-book 表和评论表的记录。
删除书籍,也需要删除对应user-book 表和评论表的记录。
TODO: 用户表 user 和 用户详情表 user-detail 表结构的关系分析
这里支持把主要信息放在用户表中,其他详情信息(用户地址,用户学习),保存在用户详情表中,便于为用户做推荐。用户详情表和用户表是一对一的关系。
具体建表语句参考
mysqldump -u root -proot --skip-add-locks --skip-add-drop-table --skip-comments novel > sql/mysql.sql
2.3.3 redis 缓存设计¶
当用户频繁下载某书籍,或者高并发下载某书籍,频繁通过 mysql 访问磁盘的数据,性能不太好。此时可以把书籍的信息通过 redis 缓存到内存中。如果用户下载过一次,那么第二次直接从缓存中读取,避免频繁访问硬盘数据。
Todo1: 当从 mysql 数据库删除一本书籍,也应该从 redis 中删除对应的缓存。
Todo2: 如果 redis 一直缓存,那么可能占用较多内存。可以写一个任务定期执行,释放缓存。
2.3.4 开发问题及解决¶
数据库端口号冲突¶
默认 mysql 的端口号是 3306 端口,如果本地装有多个 mysql 数据库,例如 docker 内部也跑的一个,可能造成另一个无法正常启动。
实际环境中不可能有两个 mysql 在不同的端口跑。所以可以本地只开发一个项目,或者临时改一下数据库的端口号等。
数据库存储小说会不会太长¶
查阅数据库资料,logntext 字段的长度足够长,存放一个 10MB 的小说也绰绰有余。
执行查询语句时,可以不返回小说详情,先返回小说的标题等信息,这样查询的速度回更快。
如果用户上传了非法文件(超过了最大上传限制),那么提示错误,不支持上传;如果少数文件特别大,可以直接放在服务器硬盘上,不需要放在数据库中。
数据库分页查找¶
如果想加载某个章节的数据,能否从 longtext 字段中返回指定的字符串,不需要一次性返回全部的页面
数据的创建时间¶
数据库执行增加操作时,通常需要 create_time 字段。这个字段可以在三个场景生成:
1、前端发出请求时,使用 new Date() 获取客户端发出请求的时间(不建议使用,也不利于网络请求)
2、后端接收到请求时,使用服务器的时间,例如 Django 或者 nodejs 的时间。
# python 内置函数
from datetime import datetime
current_time = datetime.now()
# django 内置函数
from django.utils import timezone
current_time = timezone.now()
// nodejs 内置函数
let current_time = new Date();
3、数据库执行操作时,使用 NOW() 函数生成写入数据的时间
因为后端服务和数据库设置的时间可能是一样的,也可能设置不一样的,所以这里的结果可能不同。目前个人项目中使用 NOW 函数生成创建的时间,其他项目中也有使用服务器的时间。
实际上还需要考虑服务器多机部署,集群部署等等问题,这个也需要考虑到时区问题。这也是不同服务器数据不同步的原因。如果都是国内的节点,那么数据库和服务器都设置东八区即可。
两个表是否进行关联的分析¶
在其他案例中,员工表和部门表实现了外键关联,因为这个功能是强相关的。员工必须选择一个部门,删除部门时,或者删除员工时,必须同步更新另一个表。
其他项目中,用户和评论的关系是一对多的关系,但是在 MYSQL 中并没有进行外键约束。因为这个评论和用户不属于核心业务,删除用户时也不会删除对应的评论。这个场景就使用了单表操作。
当前阅读器项目中,用户和评论的关系,也是一对多的关系,目前选择使用外键进行约束,主要作为练习。
结论:两个表是否进行关联,需要看业务场景,如果更新一个数据,需要对另一个数据进行强关联,那么就使用外键约束,否则单表也可以完成任务。
ClientClosedError: The client is closed¶
出现报错:ClientClosedError: The client is closed 这是因为 redis 的语法是 3.x 版本,最新的版本是 4.6 不匹配。
解决方案 1:可以本地重新安装旧版本,然后建立连接。目前使用这个方案。
npm install --save redis@3.1.2
解决方案 2:使用 redis 4 的语法
https://www.npmjs.com/package/redis
import { createClient } from "redis";
const client = await createClient()
.on("error", (err) => console.log("Redis Client Error", err))
.connect();
await client.set("key", "value");
const value = await client.get("key");
await client.disconnect();
2.3.5 参考链接¶
nodejs 连接 mysql: https://michael18811380328.github.io/backend/site/nodejs/24-Node.js%20%E8%BF%9E%E6%8E%A5%20MySQL/
tablePlus 数据库软件连接本地 mysql:https://blog.csdn.net/weixin_41697143/article/details/119904196