实习前:不就是 crud,能奈我何?
实习后:呜呜呜,我写不来 crud …
最近在用 GoFrame 写接口,感觉很简单,但内部细节部分,尤其是全链路的逻辑,必须捋清后去写才能做到高效且准确,边写边捋反而效果不佳。以下是 CRUD 过程中的一些思考与感悟,比较零碎,不成体系,欢迎批评指正。
1、dao、service 和 controller 如何分工?
大致总结成以下想法💡:
- dao 层只负责最基础的数据库操作,包括 Create、Update、Delete 和 Get,可以补充上 Count(统计行数)、GetList(批量获取)等。
- service 层负责稍复杂的数据库操作,但根本目的是为 controller 层的顶层业务逻辑服务,使逻辑与数据库操作解耦。
- controller 层只关注业务逻辑,在这部分几乎不出现 entity、dao、do,逻辑涉及到数据库操作就放到 service 层实现。
当然,工程实践没有绝对,如果要实现的业务逻辑确实很简单,加一个 service 反而显得浪费,那么在 controller 层做数据库操作也可以。(2.21 更新,绝对一点,controller 层不要出现数据库操作,全给爷封装到 service 层)
2、HTTP 的 Authorization 头
这部分是 HTTP 的身份认证,服务器需要客户端证明自己的身份,最常见的就是 Basic Authentication。
Basic 提供的方案是客户端凭自己的用户名和密码向服务器自证身份,传输的用户名密码信息以 用户名:密码
形式组合后,通过 base64 加密再进行传输。但由于 base64 加密是可逆的,因此 Basic 方案是不安全的。这些信息会写在 HTTP 报文的 Authorization 请求头中,例子如下:
Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
Basic 表示验证方式,后面就是 base64 加密后的 用户名:密码
信息。
3、代码规范
3.1 导包规范
尽量所有的 import
导包都遵循统一顺序,如可以采用如下顺序:
- 原生开发库
"context"
- 框架代码,如 GoFrame
"github.com/gogf/gf/v2/..."
- 第三方库
"github.com/..."
- 第三方库中与数据交互相关的
github.com/.../dao
- 自己的代码
"myproject/modules/..."
- 自己的代码中与数据交互相关的
git.in.../dao
3.2 常量统一管理
对于一些系统内置参数,如默认的管理员用户、角色ID、模块ID,权限ID等,都需要在统一文件位置下命名常量进行管理。
3.3 错误处理
有错误就返回,便于调试,返回一些提示信息。
4、数据库分页
分页的逻辑很简单,可以分为真分页和假分页,区分方式是每次翻页时都对数据库进行查询还是一次性查出所有数据。
- 前端页面能够显示在同一页面的数量有限,而存放在数据库中的数据往往很多,因此我们必须将这些数据安排到不同的页面中去。
- 当数据库的数据量很大时,一次性查询全部会很耗时,因此使用分页查询来优化。
MySQL 的分页查询语法
SELECT * FROM table_name LIMIT [offset,] rows
offset 偏移量,可选参数,表示从哪一行数据开始查询;
rows 记录行数,必需参数,表示最多返回多少行数据。
例子
SELECT * FROM students LIMIT 1000,10;
表示查询 students
表中从第 1000 行往后的 10 条数据。
5、数据库查询习惯
- 在涉及表间查询时,应使用主键,因为它是唯一且不变的属性,由主键再去查其他需要的属性。
- 不要进行频繁的 DB 操作,因为它是大开销的。在本地环境可能感受不明显,但设想一个场景,服务器启动后另一个局域网的 IP 向服务器发起请求数据库查询请求,它首先需要发起网络调用,服务器处理请求后进行数据库查询,再将数据返回给发起请求的 IP(又是一次网络调用)。这三次都是大开销操作,会使系统性能变差。典型场景:(1)多 ID 查询时,一个 ID 进行一次查询是有问题的,应该将 ID 拼为 IDs 数组,进行批量查询。(2)在
for
循环中不要进行大规模的数据库操作,如批量查询。