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

223 天前
 maotao456

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

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

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

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

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

2677 次点击
所在节点    Go 编程语言
38 条回复
Kumo31
223 天前
可以看下 Errors are values 这篇文章: https://go.dev/blog/errors-are-values
pkoukk
223 天前
db 的 error 你都敢不处理,胆子好大啊,链式操作怎么办?前一步操作失败该回滚了你还继续么
一个 crud 的接口,线上数据库字段变更没成功,查询操作失败了,抛个服务错误出来,你可以在网关加监控,捕捉到
现在 error 不处理了,等着客户投诉你你才知道啊,这么任性的么
sadfQED2
223 天前
@pkoukk 回滚?我目测 op 的数据库操作都没开启事物,回滚什么
Akkuman
223 天前
对于数据库错误,我是直接 panic 出去了,事务内的会自动回滚,然后全局 recover 了特定于数据库的报错,提示给用户的就是数据库报错,日志里面记录了错误的详细信息
K2K2
223 天前
首先写结论:必须处理 if err 判断,其实就是一个熟悉的过程,搞熟悉了就不介意了。就像菇凉一样,开始丑点,看顺了就好。
ShuWei
222 天前
是谁给了 op 这样的自信,哦,原来是因为懒和没经验,没被毒打过
xausky
222 天前
我是 if err != nill; panic(err); 然后在一个统一的地方全局处理,很多 err 确实属于没法处理,直接统一中断并且记录就好了,但是千万不要丢掉它。
maotao456
221 天前
@sadfQED2 你是怎么目测出没用事务的? 我是说 query 类操作不处理 err ,insert, update 要处理 err 。 业务系统都是 query 多过 insert 和 update 。
maotao456
221 天前
@xausky 我有提到, 将数据库操作封装一层,统一记录 error 。
maotao456
221 天前
@pkoukk 你们都不看完内容吗,我说 insert 和 update 的处理 error ,这就覆盖了链式操作。
maotao456
221 天前
@lsk569937453 这个提到了一个我没考虑到的场景,确实存在这个问题。 不是单纯的查询不到的问题。我再犹豫一下。谢谢
maotao456
221 天前
我补充一下:为什么我提出 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
221 天前
@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
221 天前
这就不得不提 try...catch...的含金量了:)
javaisthebest
221 天前
要笑死 搞到最后还是 java 的那一套 AOP 爽
pkoukk
220 天前
@maotao456 #30 链式操作就不能 insert->query->update 么?
另外第二个问题你怎么办,查询出错不报错,前端显示空数据?
你要是用户,你上来看到报个错血压高,还是看上去自己的数据全没了血压高?
maotao456
220 天前
@pkoukk
你要是用户,你上来看到报个错血压高,还是看上去自己的数据全没了血压高?

----------------------------------------------------
这个你说得有些道理,我想想
dyllen
213 天前
@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