Go连接MySQL最稳妥方式是database/sql加go-sql-driver/mysql驱动;需显式导入驱动,正确配置连接字符串,区分Query/QueryRow/Exec用途,仅用?占位防注入,手动管理事务,并显式设置连接池参数。

Go 语言连接 MySQL 最稳妥的方式是用 database/sql + github.com/go-sql-driver/mysql,不是 ORM,也不是封装层,而是标准接口+专用驱动的组合——它不隐藏细节,出错时你能直接看到 SQL 执行链路上哪一环断了。
安装驱动并建立基础连接
Go 没有内置 MySQL 驱动,必须显式引入第三方驱动。仅导入 database/sql 是不够的,会 panic:"sql: unknown driver 'mysql'"。
- 运行
go get -u github.com/go-sql-driver/mysql - 在代码中同时导入:
"database/sql"和"github.com/go-sql-driver/mysql"(后者仅需导入,无需赋值或调用) - 连接字符串格式为:
"user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true&loc=Local";注意&是 URL 中的 & 字符,不能写成& -
parseTime=true让驱动把DATETIME/TIMESTAMP自动转成time.Time;loc=Local避免时区错乱(否则可能默认 UTC)
Query、QueryRow 与 Exec 的分工
这三个方法不 interchangeable:选错会导致死锁、漏扫描、或误吞错误。
-
db.Query()用于 SELECT 多行,返回*sql.Rows,**必须调用rows.Close()**(哪怕只读一行),否则连接不会释放 -
db.QueryRow()用于确定只返回一行的 SELECT(如带 LIMIT 1 或主键查询),它内部自动 Close,但你要用.Scan()拿数据,否则 Scan 错误会被静默丢弃 -
db.Exec()用于 INSERT/UPDATE/DELETE,返回sql.Result,可调.LastInsertId()和.RowsAffected();**不能用它执行 SELECT**,否则返回空结果且无报错
防止 SQL 注入:只用问号占位符,不用字符串拼接
MySQL 驱动不支持命名参数(如 :name 或 @id),只认 ?,且参数必须是切片或单独值,不能是 map 或结构体。
启科网络商城系统由启科网络技术开发团队完全自主开发,使用国内最流行高效的PHP程序语言,并用小巧的MySql作为数据库服务器,并且使用Smarty引擎来分离网站程序与前端设计代码,让建立的网站可以自由制作个性化的页面。 系统使用标签作为数据调用格式,网站前台开发人员只要简单学习系统标签功能和使用方法,将标签设置在制作的HTML模板中进行对网站数据、内容、信息等的调用,即可建设出美观、个性的网站。
立即学习“go语言免费学习笔记(深入)”;
- 正确:
db.Query("SELECT name FROM users WHERE id > ?", minID)或db.Query("SELECT * FROM logs WHERE level IN (?, ?)", "warn", "error") - 错误:
"SELECT * FROM users WHERE name = '" + name + "'"—— 直接给注入留门 - 错误:
db.Query("SELECT * FROM users WHERE id IN (?)", []int{1,2,3})—— ? 只展开为单个值,不会变成IN (1,2,3);需动态拼?, ?, ?再传参
事务控制:Begin → Exec/Query → Commit/Rollback
事务不是自动开启的,每次 db.Query 或 db.Exec 都是独立语句。要跨多步原子操作,必须显式管理事务对象。
- 用
tx, err := db.Begin()获取事务,后续所有操作都调tx.Query/tx.Exec - 成功后调
tx.Commit();失败必须调tx.Rollback(),否则连接会卡在“事务中”状态,最终被连接池回收时触发 warning - 注意:事务内不能混用
db.*和tx.*,否则语句脱离事务上下文 - 如果中间某步出错忘了 Rollback,又没 defer,这个事务连接大概率会在下次复用时因状态异常被丢弃
最常被忽略的是连接池行为:默认最大打开连接数是 0(无限制),但在高并发下容易耗尽 MySQL 的 max_connections;建议显式调 db.SetMaxOpenConns(n) 和 db.SetMaxIdleConns(n),否则线上跑几天后可能突然大量超时,而错误日志里只显示 “i/o timeout”,实际是连接等不到空闲槽位。









