SQLite是Go语言学习阶段最务实的本地存储方案,推荐使用glebarez/go-sqlite驱动;务必调用db.Ping()验证连接,路径用绝对路径或":memory:",CRUD需显式事务,先掌握database/sql再用GORM。

sqlite 不是 Go 的原生数据库,但它是语言学习阶段最务实的本地化存储方案——不用搭服务、不依赖 Docker、单文件可携带,写完就能跑。
选哪个驱动?别被 mattn/go-sqlite3 绑死
初学者常卡在第一步:装完 go get github.com/mattn/go-sqlite3 就报错 exec: "gcc": executable file not found。这不是你环境问题,是这个驱动必须用 CGO 编译,Windows 上没 MinGW、Mac 上没 Xcode Command Line Tools、Linux 上没 build-essential,它就起不来。
-
modernc.org/sqlite:纯 Go 实现,go build直接过,适合快速验证逻辑,但暂不支持PRAGMA journal_mode = WAL等高级特性 -
github.com/glebarez/go-sqlite:也是纯 Go,API 兼容database/sql,对 WAL 和内存数据库支持更稳,推荐语言学习期主力使用 -
mattn/go-sqlite3:性能略高(尤其批量写入),但部署门槛高,只建议在你明确要上线、且能控制构建环境时才引入
sql.Open 后一定要 db.Ping()
很多人写完 sql.Open("sqlite", "data.db") 就直接 Exec,结果插入无声无息——因为 sql.Open 只是“准备连接”,不真正建链。SQLite 文件路径写错、目录没写权限、磁盘满,全都会在第一次 Exec 或 Query 时才暴露,错误堆栈还藏得深。
- 加一行
err := db.Ping(),立刻捕获底层 I/O 问题 - 路径别用相对路径裸写,比如
"./db.sqlite";改用filepath.Join(os.TempDir(), "myapp.db")或显式指定绝对路径,避免因工作目录变动导致文件创建失败 - 如果只是临时测试,用
":memory:"——它不落地、不占磁盘,重启即空,适合单元测试和语法练手
事务不是可选项,而是防崩底线
学 CRUD 时容易忽略事务。比如你写个“注册用户+初始化配置”两步操作,中间出错(网络抖动、磁盘满、字段超长),没事务就会留下半残数据:用户进了表,配置没写进去,下次再注册又冲突。
- 哪怕只有单条
INSERT,也建议包一层tx, err := db.Begin(),成功后tx.Commit(),失败则tx.Rollback() - SQLite 默认隔离级别是
DEFERRED,并发读写时注意加锁逻辑,别指望它自动解决竞态 - 不要在事务里调
db.QueryRow后再Scan,而要用tx.QueryRow——否则会从连接池拿新连接,脱离事务上下文
GORM 适合练模型,但先搞懂 database/sql
很多教程一上来就推 gorm.Open(sqlite.Open("test.db")),结果字段映射不对、时间类型乱码、外键不生效,debug 半天才发现是 GORM 自动加了 NOT NULL 或用了 SQLite 不支持的语法。
立即学习“go语言免费学习笔记(深入)”;
- 语言学习阶段,先用原生
database/sql写 3–5 个完整 CRUD,亲手拼 SQL、处理rows.Scan、理解sql.NullString为什么存在 - 等你能徒手写出带事务、带预处理、带错误分类(
sql.ErrNoRowsvs 其他)的代码,再上 GORM;否则它只是把问题藏得更深 - 真要用 GORM,记得关掉日志:
&gorm.Config{Logger: logger.Default.LogMode(logger.Silent)},不然满屏 SQL 会干扰你观察实际执行流


















