Golang: Library: go-sql-driver/mysql

11th October 2021 at 3:09pm

流行的 Golang MySQL driver。

DSN

DSN 即 Data Source Name,在一些地方也称 connection string。完整格式是:

[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

例子见 文档

重要参数

DSN 中可以设置各种参数。有一些参数是比较重要的,列举在这里。

字符编码及 collation

Driver 默认指定了 utf8mb4_general_ci 为 collation。另外一个选择是 utf8mb4_unicode_ci

  • utf8mb4_unicode_ci 更准确,比如如果你要使用德文字典序,那么需要用它
  • utf8mb4_general_ci 更快,但是在一些排序上稍微不准确

至于具体用哪个:

  • 这里 认为 unicode_ci 更好;认为 general_ci 带来的性能提升很小
  • Django 认为 假如你看重 unicode_ci 带来的排序准确性,那么用它;否则用 general_ci

我认为直接用 unicode_ci 好一点。因此应添加:collation=utf8mb4_unicode_ci

Charset 不需要指定。

时区相关

  • parseTime:表示是否把 MySQL 中的 DATE DATETIMETIMESTAMP 列转换成 time.Time(虽然文档没有提及 TIMESTAMP 会被转换,但 事实上 它是会被转换的)。默认为 false,建议改为 true
  • loc:当 parseTime 为 true 时起作用;会设置转换出来的 time.Time 变量的时区。默认是 UTC,建议设置成与 MySQL 的 time_zone 变量一样的时区。可选的值有:
    • "UTC"
    • "Local"(表示你的 Go 程序运行的本机时区)
    • 更具体的 "Asia/Shanghai"
  • time_zone:是 MySQL 的 system variable;可以设置本次连接所使用的时区:
    • 影响范围:
      • 时区敏感的数据的存储和展示。比如 NOW() CURTIME() 返回值的展示;TIMESTAMP 列在存储时会按 time_zone 的时区转换成 UTC 存储,在读取时再转换成 time_zone 的时区
      • DATE TIME DATETIME 是时区无关的,它们的存储与展示不受 time_zone 变量影响;但是当他们被转换为 TIMESTAMP 值时,time_zone 会起作用
    • time_zone=%27Asia%2FShanghai%27 等同于在 MySQL 中执行 SET time_zone='Asia/Shanghai'
    • 但很多 MySQL 实例默认是没有加载时区信息的(可以看系统 schema mysql.time_zone_name 中有无行),需要运维导入一次。因此你设置时区为 Asia/Shanghai 时 MySQL 可能并不认识;可以将值设置成 offset,如 '+8:00'

综上所述,建议的参数汇总如下:

parseTime=true&loc=Asia%2FShanghai&time_zone=%27%2B8%3A00%27

超时控制

Driver 默认不设超时时间(无限制)。相关参数:

  • timeout:建立连接时的超时时间,建议 2~5s
  • readTimeout:I/O 读超时时间。视应用程序读数据量大小,建议 2~20s
  • writeTimeout:I/O 写超时时间。视应用程序写数据量大小,建议 2~20s

综上所述,超时控制、建议的参数汇总如下:

timeout=2s&readTimeout=2s&writeTimeout=2s

此外,还有连接池相关的参数,比如 MaxOpenConnsMaxIdleConns 等,这些通过 Golang 的 database/sql 包的接口、或者 GORM 的参数来设置。