go-sqlite3驱动编译失败需启用cgo并安装对应平台c库:macos用brew install sqlite3并装xcode命令行工具,windows改用glebarez/sqlite纯go驱动,linux装libsqlite3-dev并设cgo_enabled=1。

能跑通,但默认 sqlite3 驱动在 macOS 和 Windows 上容易编译失败——不是 Gin 的问题,是驱动本身依赖 C 代码,跨平台构建要额外处理。
sqlite3 驱动安装失败时怎么办
执行 go get github.com/mattn/go-sqlite3 报错 “clang: error: linker command failed” 或 “cannot find -lsqlite3”,说明本地没装 SQLite C 库或编译环境不全。
- macOS:用
brew install sqlite3,再确保 Xcode 命令行工具已安装(xcode-select --install) - Windows:推荐改用
github.com/glebarez/sqlite(纯 Go 实现,无 CGO 依赖),替换 import 和连接字符串即可 - Linux(Ubuntu/Debian):
sudo apt-get install libsqlite3-dev,然后加CGO_ENABLED=1环境变量再go build - 如果只是本地开发调试,临时关 CGO 也能绕过(
CGO_ENABLED=0 go run main.go),但必须用纯 Go 驱动(如glebarez/sqlite)
sqlx.Connect 和 db.Ping 必须配对用
只调 sqlx.Connect("sqlite3", dsn) 不等于数据库就 ready 了——它只做参数解析和 driver 初始化,不真正连库。常见现象是后续 db.Get() 突然 panic “no such table”,但没报连接错误。
- 初始化后立刻加
err = db.Ping(),否则无法捕获文件权限、路径不存在、磁盘满等底层问题 - SQLite 的
dsn是文件路径,比如"./data/app.db";路径不存在时会自动创建文件,但父目录必须存在,否则Ping()返回no such file or directory - 如果要用内存数据库测试(不落盘),写
":memory:",但注意每次重启进程都会丢失数据,不能用于生产
Gin 路由里怎么安全传参查 SQLite
别直接拼 SQL 字符串,尤其涉及 id、username 这类用户输入字段——SQLite 虽轻量,但 SQL 注入一样生效。
- 所有查询必须用问号占位符 +
db.QueryRow()或db.Select(),例如:db.QueryRow("SELECT id FROM users WHERE username = ?", username) - 路径参数(如
/user/:id)取值后,先转成整型再进 SQL,避免字符串注入:id, _ := strconv.Atoi(c.Param("id")) - WHERE 条件含多个可选字段(如搜索接口),用
sqlx.In()+sqlx.Rebind()处理变长 IN 查询,别手写逗号拼接 - INSERT 时用
db.NamedExec()配结构体,字段名自动映射,比手动列字段更防错
SQLite 在 Gin 里做并发写要注意什么
SQLite 默认是“写阻塞”模型:一个写事务进行中,其他写请求会等待甚至超时(默认 5 秒),而 Gin 默认每个请求开 goroutine,高并发下容易卡住或返回 database is locked。
- 启动时给 DSN 加
?_busy_timeout=10000(单位毫秒),延长等待上限,例如:"./app.db?_busy_timeout=10000" - 读操作尽量用
db.QueryRowContext()带 context,设 timeout 防止长尾请求拖垮整个服务 - 避免在单个 HTTP 请求里开多个写事务(比如先 INSERT 再 UPDATE 同一表),合并成一个事务更稳
- 如果真需要高并发写,要么换 Genji(纯 Go、支持 WAL 模式),要么上 MySQL —— SQLite 不是为这个场景设计的
SQLite 嵌入式部署省事,但它的锁机制、无用户权限、无远程访问这些“省事”的代价,得在路由设计、参数校验、事务粒度上提前兜住。别等压测时才看到 database is locked。











