惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Vercel News
Vercel News
F
Fortinet All Blogs
月光博客
月光博客
G
Google Developers Blog
博客园 - Franky
GbyAI
GbyAI
The Cloudflare Blog
I
InfoQ
雷峰网
雷峰网
WordPress大学
WordPress大学
罗磊的独立博客
大猫的无限游戏
大猫的无限游戏
T
The Blog of Author Tim Ferriss
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
小众软件
小众软件
腾讯CDC
B
Blog
量子位
V
V2EX
S
SegmentFault 最新的问题
Google DeepMind News
Google DeepMind News

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例)
避免全局变量
Jiajun Huang · 2018-11-15 · via Jiajun的技术笔记

避免全局变量

睡觉前好像确实不应该想问题,大半夜的思维活跃睡不着了。当然,那只臭蚊子也有功劳,要是被我发现了我要灭了它。 不过,既然睡不着,那就起来写篇博客。

最近突然想到以前的一个项目,一个用来做token认证的微服务,当时为了快速实现,没有严格遵守MVC,很多controller里就有类似的 代码:

func XXXHandler() {
    db.Where("xxx = ?", 123).Find(&User)
}

后来同事接入opentracing的时候,就很痛苦。当然了,来新公司之后也写过类似的代码,主要是之前没有想到特别好的解决方案,以及 严格遵守MVC的必要性。Go的ORM实在是太难用了,以至于无法完全的将对象和数据库表解耦,如你所见,代码里还到处都是SQL的影子。 如果是SQLAlchemy还真的很难看出这样做有什么不好。像上面的代码,至少有这么几个坏处:

  • 暴露了具体SQL实现给外界,此处的外界是Controller。因为Go的ORM特别难用,里面嵌入了大量的SQL语句,所以其实是和具体数据库 强相关的。也就是说,这样以来,假设啥时候要改个数据库,那就完蛋了,因为到处充斥着这样的代码,手都能改断。

  • 没有重复利用代码。举个例子,根据 user_idUser 信息的代码,肯定到处都需要。如果所有的地方都是直接 db.Where(xxx) 这样的用法,就会造成和上面一条说到的一样的问题。

  • 无法对数据库操作进行一些特定的,统一的操作。举个例子,加tracing。如果我们把提取数据的函数封装在M里,那么我们在每个方法 里加一行 defer BlablaTracing() 就可以达到我们的目的,但是像上面那样,就不好办了。

所以正确的方法应该是,遵循MVC。把数据库操作封装到M里,例如,model层这样写:

var db sql.DB // 不暴露db出去,把db限制在model这个包里

type User struct{}

func GetUserByID(id uint32) (*User, error) {
	user := User{}
	if err := db.Where("id = ?", id).Find(&user).Error; err != nil {
		return nil, err
	} else {
		return user, nil
	}
}

然后,controller里这样写:

func XXXHandler() {
    user, err := GetUserByID(user_id)
    xxxxxx
}

所以说,有些懒,偷不得。为了不让同事想开车从你身上碾几遍,还是好好设计,好好想好少挖坑吧😁