1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 04:22:22 +00:00
This commit is contained in:
Xargin 2019-01-01 20:42:10 +08:00
parent 092b2f1ebd
commit d153a2b6c4

View File

@ -1,6 +1,6 @@
# 5.5 Database 和数据库打交道
本节将对`db/sql`官方标准库作一些简单分析并介绍一些应用比较广泛的开源ORM和sql builder。并从企业级应用开发和公司架构的角度来分析哪种技术栈对于现代的企业级应用更为合适。
本节将对`db/sql`官方标准库作一些简单分析并介绍一些应用比较广泛的开源ORM和SQL Builder。并从企业级应用开发和公司架构的角度来分析哪种技术栈对于现代的企业级应用更为合适。
## 5.5.1 从 database/sql 讲起
@ -102,7 +102,7 @@ func main() {
聪明如你的话,在上面这段简短的程序中可能已经嗅出了一些不好的味道。官方的`db`库提供的功能这么简单,我们每次去数据库里读取内容岂不是都要去写这么一套差不多的代码?或者如果我们的对象是结构体,把`sql.Rows`绑定到对象的工作就会变得更加得重复而无聊。
是的,所以社区才会有各种各样的sql builder和orm百花齐放。
是的,所以社区才会有各种各样的SQL Builder和ORM百花齐放。
## 5.5.2 提高生产效率的ORM和SQL Builder
@ -143,7 +143,7 @@ o := orm.NewOrm()
num, err := o.QueryTable("cardgroup").Filter("Cards__Card__Name", cardName).All(&cardgroups)
```
很多ORM都提供了这种Filter类型的查询方式不过实际上在某些ORM背后甚至隐藏了非常难以察觉的细节比如生成的sql语句会自动 limit 1000
很多ORM都提供了这种Filter类型的查询方式不过实际上在某些ORM背后甚至隐藏了非常难以察觉的细节比如生成的SQL语句会自动`limit 1000`
也许喜欢ORM的读者读到这里会反驳了你是没有认真阅读文档就瞎写。是的尽管这些ORM工具在文档里说明了All查询在不显式地指定Limit的话会自动limit 1000但对于很多没有阅读过文档或者看过ORM源码的人这依然是一个非常难以察觉的“魔鬼”细节。喜欢强类型语言的人一般都不喜欢语言隐式地去做什么事情例如各种语言在赋值操作时进行的隐式类型转换然后又在转换中丢失了精度的勾当一定让你非常的头疼。所以一个程序库背地里做的事情还是越少越好如果一定要做那也一定要在显眼的地方做。比如上面的例子去掉这种默认的自作聪明的行为或者要求用户强制传入limit参数都是更好的选择。
@ -157,7 +157,7 @@ num, err := o.QueryTable("cardgroup").Filter("Cards__Card__Name", cardName).All(
当然我们不能否认ORM的进步意义它的设计初衷就是为了让数据的操作和存储的具体实现所剥离。但是在上了规模的公司的人们渐渐达成了一个共识由于隐藏重要的细节ORM可能是失败的设计。其所隐藏的重要细节对于上了规模的系统开发来说至关重要。
相比ORM来说sql builder在sql和项目可维护性之间取得了比较好的平衡。首先sql builer不像ORM那样屏蔽了过多的细节其次从开发的角度来讲sql builder简单进行封装后也可以非常高效地完成开发举个例子
相比ORM来说SQL Builder在SQL和项目可维护性之间取得了比较好的平衡。首先sql builer不像ORM那样屏蔽了过多的细节其次从开发的角度来讲SQL Builder简单进行封装后也可以非常高效地完成开发举个例子
```go
where := map[string]interface{} {
@ -170,17 +170,17 @@ orderBy := []string{"id asc", "create_time desc"}
orders := orderModel.GetList(where, limit, orderBy)
```
sql builder的相关代码或者读懂都不费劲。把这些代码脑内转换为sql也不会太费劲。所以通过代码就可以对这个查询是否命中数据库索引是否走了覆盖索引是否能够用上联合索引进行分析了。
SQL Builder的相关代码或者读懂都不费劲。把这些代码脑内转换为sql也不会太费劲。所以通过代码就可以对这个查询是否命中数据库索引是否走了覆盖索引是否能够用上联合索引进行分析了。
说白了sql builder是sql在代码里的一种特殊方言如果你们没有DBA但研发有自己分析和优化sql的能力或者你们公司的DBA对于学习这样一些sql的方言没有异议。那么使用sql builder是一个比较好的选择不会导致什么问题。
说白了SQL Builder是sql在代码里的一种特殊方言如果你们没有DBA但研发有自己分析和优化sql的能力或者你们公司的DBA对于学习这样一些sql的方言没有异议。那么使用SQL Builder是一个比较好的选择不会导致什么问题。
另外在一些本来也不需要DBA介入的场景内使用sql builder也是可以的例如你要做一套运维系统且将MySQL当作了系统中的一个组件系统的QPS不高查询不复杂等等。
另外在一些本来也不需要DBA介入的场景内使用SQL Builder也是可以的例如你要做一套运维系统且将MySQL当作了系统中的一个组件系统的QPS不高查询不复杂等等。
一旦你做的是高并发的OLTP在线系统且想在人员充足分工明确的前提下最大程度控制系统的风险使用sql builder就不合适了。
一旦你做的是高并发的OLTP在线系统且想在人员充足分工明确的前提下最大程度控制系统的风险使用SQL Builder就不合适了。
## 5.5.3 脆弱的数据库
无论是ORM还是sql builder都有一个致命的缺点就是没有办法进行系统上线的事前sql审核。虽然很多ORM和sql builder也提供了运行期打印sql的功能但只在查询的时候才能进行输出。而sql builder和ORM本身提供的功能太过灵活。使得你不可能通过测试枚举出所有可能在线上执行的sql。例如你可能用sql builder写出下面这样的代码
无论是ORM还是SQL Builder都有一个致命的缺点就是没有办法进行系统上线的事前sql审核。虽然很多ORM和SQL Builder也提供了运行期打印sql的功能但只在查询的时候才能进行输出。而SQL Builder和ORM本身提供的功能太过灵活。使得你不可能通过测试枚举出所有可能在线上执行的sql。例如你可能用SQL Builder写出下面这样的代码
```go
where := map[string]interface{} {
@ -201,9 +201,9 @@ res, err := historyModel.GetList(where, limit, orderBy)
对于现在7乘24服务的互联网公司来说服务不可用是非常重大的问题。存储层的技术栈虽经历了多年的发展在整个系统中依然是最为脆弱的一环。系统宕机对于24小时对外提供服务的公司来说意味着直接的经济损失。个中风险不可忽视。
从行业分工的角度来讲,现今的互联网公司都有专职的 DBA。大多数DBA并不一定有写代码的能力去阅读sql builder的相关“拼sql”代码多多少少还是会有一点障碍。从DBA角度出发还是希望能够有专门的事前sql审核机制并能让其低成本地获取到系统的所有sql内容而不是去阅读业务研发编写的sql builder的相关代码。
从行业分工的角度来讲现今的互联网公司都有专职的DBA。大多数DBA并不一定有写代码的能力去阅读SQL Builder的相关“拼SQL”代码多多少少还是会有一点障碍。从DBA角度出发还是希望能够有专门的事前SQL审核机制并能让其低成本地获取到系统的所有SQL内容而不是去阅读业务研发编写的SQL Builder的相关代码。
所以现如今,大型的互联网公司核心线上业务都会在代码中把sql放在显眼的位置提供给DBA评审举一个例子
所以现如今,大型的互联网公司核心线上业务都会在代码中把SQL放在显眼的位置提供给DBA评审举一个例子
```go
const (