关于 Golang 不处理数据库操作的 error 的一点思考

2023-10-20 14:38:42 +08:00
 maotao456

事情的起因是这样的。 一个方法要查询 N 次数据库,每一次查询都要 if err , 我实在受不了啦,思索一番后觉得 似乎并不需要在运行时处理数据库操作的 error 。结论如下:

因为运行时的 error 大概率是连接,基建问题。 如果是 sql 语句问题,早就该在测试环节就发现。 既然是连接问题,那么一个查询报错,其它所有查询都会报错, 所以在每一个查询的地方都做 err check 是没有意义的。

可是不处理 err 怎么知道数据库有问题呢,怎么保证业务的完整呢?我大概理出了三板斧:

  1. query 的操作不处理 err ,sql 问题留到测试期解决
  2. update, insert 类操作要处理 err, 保证数据安全
  3. 对这些操作做一层包装和封装,每次调用记录 error ,监控该报警报警

当然,我不确定我这个想法是否考虑周到,可能以偏概全了。 欢迎大家一起讨论一下。

3010 次点击
所在节点    Go 编程语言
38 条回复
Kumo31
2023-10-20 18:14:13 +08:00
可以看下 Errors are values 这篇文章: https://go.dev/blog/errors-are-values
pkoukk
2023-10-20 18:35:33 +08:00
db 的 error 你都敢不处理,胆子好大啊,链式操作怎么办?前一步操作失败该回滚了你还继续么
一个 crud 的接口,线上数据库字段变更没成功,查询操作失败了,抛个服务错误出来,你可以在网关加监控,捕捉到
现在 error 不处理了,等着客户投诉你你才知道啊,这么任性的么
sadfQED2
2023-10-20 19:24:31 +08:00
@pkoukk 回滚?我目测 op 的数据库操作都没开启事物,回滚什么
Akkuman
2023-10-20 21:31:27 +08:00
对于数据库错误,我是直接 panic 出去了,事务内的会自动回滚,然后全局 recover 了特定于数据库的报错,提示给用户的就是数据库报错,日志里面记录了错误的详细信息
K2K2
2023-10-20 21:37:16 +08:00
首先写结论:必须处理 if err 判断,其实就是一个熟悉的过程,搞熟悉了就不介意了。就像菇凉一样,开始丑点,看顺了就好。
ShuWei
2023-10-20 23:56:02 +08:00
是谁给了 op 这样的自信,哦,原来是因为懒和没经验,没被毒打过
xausky
2023-10-21 14:55:20 +08:00
我是 if err != nill; panic(err); 然后在一个统一的地方全局处理,很多 err 确实属于没法处理,直接统一中断并且记录就好了,但是千万不要丢掉它。
maotao456
2023-10-21 22:27:02 +08:00
@sadfQED2 你是怎么目测出没用事务的? 我是说 query 类操作不处理 err ,insert, update 要处理 err 。 业务系统都是 query 多过 insert 和 update 。
maotao456
2023-10-21 22:27:48 +08:00
@xausky 我有提到, 将数据库操作封装一层,统一记录 error 。
maotao456
2023-10-21 22:29:42 +08:00
@pkoukk 你们都不看完内容吗,我说 insert 和 update 的处理 error ,这就覆盖了链式操作。
maotao456
2023-10-21 22:31:29 +08:00
@lsk569937453 这个提到了一个我没考虑到的场景,确实存在这个问题。 不是单纯的查询不到的问题。我再犹豫一下。谢谢
maotao456
2023-10-21 22:38:18 +08:00
我补充一下:为什么我提出 query 类操作不处理 err ,我的考虑是这样的,
查询结果无非两种,是 struct 或者是 slice

一般来说,无论是什么查询结果,我们都会且有必要验证结果的有效性(而不仅仅是 err )。
比如说:
1. 如果查询结果是一个 struct ,那么至少会 if xx != nil
2. 如果查询结果是一个 slice ,一般至少会判断 len(slice) > 0

在这两个前提下,无论有没有 err 都会去做的处理。 ( for 类操作甚至不需要不需要提前 len(slice))
重点: 一旦发生 error, 那么这两种查询的结果一定是 nil 和 len(slice) = 0, 所以对于预期来说并没有任何差异。
maotao456
2023-10-21 22:47:15 +08:00
@maotao456 并且,if err != nil 的判断并不能替代业务上的 if struct != nil or if len(slice) > 0 , 因为即使没有 error 发生。 我从来不会以 error 有没有来判断数据正不正确。 而是以数据本身判断数据是否正确。

伪代码如下:

var entity user
err := sqlx.Get("select * from xx limit 1;", &user)
if err != nil {
logger.Error("xxxxxxxxxxxxxxxxxxxxx");
return err
}

if user.ID == 0 {
return errors.New("user not found")
}

在这段代码中,重点只在与有没有写日志。 有没有 if err 都不影响业务逻辑的流程。

那么, 换个角度来说,是否所有数据库操作都可以统一写日志呢,业务中的 query 操作是否可以不显示处理 error 呢, 单看这个例子似乎是可以的。

slice 查询操作场景你们也可以代入看看。
lanlanye
2023-10-21 23:38:19 +08:00
这就不得不提 try...catch...的含金量了:)
javaisthebest
2023-10-22 12:17:13 +08:00
要笑死 搞到最后还是 java 的那一套 AOP 爽
pkoukk
2023-10-23 10:16:45 +08:00
@maotao456 #30 链式操作就不能 insert->query->update 么?
另外第二个问题你怎么办,查询出错不报错,前端显示空数据?
你要是用户,你上来看到报个错血压高,还是看上去自己的数据全没了血压高?
maotao456
2023-10-23 11:58:12 +08:00
@pkoukk
你要是用户,你上来看到报个错血压高,还是看上去自己的数据全没了血压高?

----------------------------------------------------
这个你说得有些道理,我想想
dyllen
2023-10-30 15:58:36 +08:00
@Morii 还是一样的,go 的 sql 标准库也是这样。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/983809

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX