TiDB 完全兼容 MySQL 协议,可用 database/sql + go-sql-driver/mysql 直连;需设 parseTime=true、注意 autocommit 行为、DSN 不写 charset、检查监听地址与权限、启用 TLS 时配置 tls 参数、批量插入用多值语句或 Prepare、事务内读不到新写数据是因默认 REPEATABLE READ 快照隔离。

用 database/sql 连 TiDB 和连 MySQL 几乎没区别
TiDB 完全兼容 MySQL 协议,Go 的标准库 database/sql 配合任意支持 MySQL 协议的驱动(比如 github.com/go-sql-driver/mysql)就能直连,不需要额外适配层或专用 SDK。
常见错误是误以为要换驱动 —— 实际上只要 DSN 格式对、端口开、账号有权限,sql.Open("mysql", dsn) 就能跑通。
- DSN 必须显式指定
parseTime=true,否则TIME/DATETIME字段会变成字符串,不是time.Time - TiDB 默认不启用
autocommit,但 Go 的db.Query默认走自动提交;手动事务必须用db.Begin()+tx.Commit() - 连接字符串里别写
charset=utf8mb4—— TiDB 5.0+ 已默认使用该字符集,硬写可能触发旧版驱动的解析 bug
ping 失败但 DSN 看起来完全正确?先查这三件事
典型现象:sql.Open 成功,但 db.Ping() 返回 dial tcp: i/o timeout 或 invalid connection,而 telnet 或 mysql 命令行能连上。
- 检查 TiDB server 是否监听
0.0.0.0:4000而非127.0.0.1:4000—— Docker 或 Kubernetes 环境下容易只绑本地回环 - 确认用户权限:TiDB 的
GRANT语法和 MySQL 一致,但CREATE USER 'u'@'%'后必须显式GRANT ALL ON *.* TO 'u'@'%',不能省略@'%' - Go 驱动默认启用
tls=false;如果 TiDB 开了强制 TLS(security.require-secure-transport = true),DSN 得加&tls=skip-verify或配好 CA
批量插入性能差?别直接用 Exec 循环
TiDB 的事务模型和 MySQL 不同:单条 INSERT 会触发一次两阶段提交,循环执行 1000 次就是 1000 次网络往返 + 1000 次协调开销。
立即学习“go语言免费学习笔记(深入)”;
- 用
INSERT INTO t VALUES (),(),()...拼成多值语句,单次Exec插入最多 1 万行(TiDB v6.1+ 推荐上限) - 更稳的方式是走
db.Prepare+stmt.Exec批量参数,避免 SQL 注入且复用执行计划 - 如果数据量超 10 万行,优先考虑
LOAD DATA LOCAL INFILE(需客户端和服务端都开启secure_file_priv)或 TiDB Lightning 工具
事务里读不到刚写的行?不是 bug,是 TiDB 的默认隔离级别
现象:在同一个 *sql.Tx 中,tx.Exec("INSERT ...") 后立刻 tx.Query("SELECT ..."),查不到刚插的数据。这不是 Go 驱动问题,是 TiDB 默认用 REPEATABLE READ 隔离级别,快照基于事务开始时刻。
- 临时解决:在 DSN 末尾加
&tx_isolation=READ-COMMITTED(TiDB 4.0+ 支持),让事务内读取最新已提交版本 - 长期建议:业务逻辑尽量避免“写后即读”,改用
SELECT ... FOR UPDATE显式加锁,或拆成两个事务(写完 commit,再开新事务读) - 注意
autocommit=1时每个语句都是独立事务,不存在这个问题 —— 但会失去跨语句一致性保障
最常被忽略的是:TiDB 的 REPEATABLE READ 不像 MySQL 那样提供“当前读”语义,它真就是快照读,连 SELECT ... LOCK IN SHARE MODE 都不支持。










