Go MySQL
使用 go-sql-driver/mysql,但是它是一个驱动,使用使用 SQL 的 CRUD,还是要看 Go 的标准库 database/sql。 看起来有些蛋疼,但我觉得这是 Go 标准化做的好的一个体现。不管是你用的什么 SQL,只要有驱动,就可以一视同仁。 这样的话,比如从 MySQL 到 MS SQL Server,只需要在初始化的做一下变更,其它部分代码基本上不需要动。
驱动列表可以见:https://github.com/golang/go/wiki/SQLDrivers
官方的使用范例:https://github.com/golang/go/wiki/SQLInterface
Python 也提供了 PEP 249 – Python Database API Specification v2.0,但它更像是一个协议上的约束,并不是实际限制库的实现。
使用标准库对 DB 操作时,需要手写 SQL 的 CRUD,一方面不方便,另外一方面也不安全。有一些包提供 SQL 构建器(用来生成 SQL 语句)。
比如:doug-martin/goqu,你可以这样:
ds := goqu.Insert("user"). Cols("first_name", "last_name"). Vals( goqu.Vals{"Greg", "Farley"}, goqu.Vals{"Jimmy", "Stewart"}, goqu.Vals{"Jeff", "Jeffers"}, ) insertSQL, args, _ := ds.ToSQL() fmt.Println(insertSQL, args)
会输出:
INSERT INTO "user" ("first_name", "last_name") VALUES ('Greg', 'Farley'), ('Jimmy', 'Stewart'), ('Jeff', 'Jeffers') []
它是一个 SQL 语句生成器,并不会实际的执行。
再比如:squirrel ,你可以这样:
sql, args, err := sq. Insert("users").Columns("name", "age"). Values("moe", 13).Values("larry", sq.Expr("? + 5", 12)). ToSql()
它会生成:
sql == "INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)"
但是它也允许直接执行 SQL 语句:
stooges := users.Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}}) three_stooges := stooges.Limit(3) rows, err := three_stooges.RunWith(db).Query()
等价于:
rows, err := db.Query("SELECT * FROM users WHERE username IN (?,?,?,?) LIMIT 3", "moe", "larry", "curly", "shemp")
goqu 和 squirrel 是社区比较出名的两个 SQL 构建器。我自己使用下来:
- goqu 基本上没有什么学习成本,也很好 debug,但自己还是要封装 SQL 调用和异常处理;
- squirrel 基本上封装了 SQL 调用这一层,自己全做了,用起来省事,但有一定的学习成本;
具体用哪个看个人。
squirrel 用习惯了真舒服,推荐!
MySQL 连接是时区和 time
解析问题,需要设置 DSL 参数: parseTime=true&loc=Asia%2FShanghai
,否则 time 解析不了,而且时区有可能是错的。
DSL 全路径 `${username}:${password}@tcp(${address})/${dbname}`
。
Facebook 开源的 ent 框架,类似 ORM,做到 entity 到数据表 scheme 的映射。使用起来比较简单,推荐。
关于读写分离的一个最佳实践:单独 Get 一个实体的时候,从主库读。List 的时候从从库读。不管主从复制有多快,总会有一些慢 SQL 卡住。 在一般的 RESTful 使用中,Create 之后会立刻 Get,遇到慢 SQL 就会查不到数据。