SQLite 是嵌入式数据库,不需要独立的服务进程。一个文件就是一个数据库,部署简单到极致。虽然不适合高并发场景,但在特定场景下是绝佳选择。
go get -u gorm.io/driver/sqlite
底层使用 github.com/mattn/go-sqlite3,这是一个 CGO 库,编译时需要 GCC 环境。
package main
import (
"fmt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic("连接失败")
}
fmt.Println("连接成功")
}
test.db 是数据库文件路径。文件不存在会自动创建。
SQLite 支持纯内存数据库,适合测试和临时缓存:
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
内存数据库速度极快,但进程退出后数据丢失。单元测试中广泛使用。
多个连接共享同一个内存数据库:
db1, _ := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
db2, _ := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
不加 cache=shared,每个连接是独立的内存数据库。
import "gorm.io/driver/sqlite"
sqliteConfig := sqlite.Config{
DriverName: "sqlite3",
DSN: "test.db",
}
db, err := gorm.Open(&sqliteConfig, &gorm.Config{})
DriverName
默认是 sqlite3,除非注册了自定义驱动,一般不需要改。
DSN
数据源名称,可以是文件路径或内存标识。
SQLite 不是万能的,但在这些场景下表现出色:
桌面应用
Electron、Wails、Fyne 等桌面框架开发的本地应用,SQLite 是首选数据存储方案。用户数据存在本地,无需网络。
移动应用
Android、iOS 都内置 SQLite 支持。Go 编译到移动端时,SQLite 是天然的本地数据库选择。
嵌入式设备
树莓派、路由器等资源受限设备,跑不动 MySQL,但 SQLite 完全没问题。
开发测试
本地开发时用 SQLite 替代 MySQL,省去安装和配置的麻烦。单元测试用内存数据库,速度快且隔离。
小型项目
访问量不大的内部工具、个人项目,SQLite 足够用。一个文件搞定一切,备份就是复制文件。
原型开发
快速验证想法时,先用 SQLite 跑起来,后期再迁移到正式数据库。
这些场景应该避免使用 SQLite:
高并发写入
SQLite 写操作会锁整个数据库,并发写入性能差。如果每秒写入超过几十次,考虑 PostgreSQL 或 MySQL。
网络访问
SQLite 是本地文件,不能通过网络访问。多服务器共享数据必须用独立数据库服务。
大数据量
单文件数据库,数据量大了备份和迁移都麻烦。建议单库不超过几百 GB。
复杂查询
SQLite 不支持存储过程、触发器等高级特性,复杂业务逻辑需要应用层实现。
SQLite 的并发模型比较特殊:
GORM 默认配置下,SQLite 会启用 WAL 模式提升并发:
db.Exec("PRAGMA journal_mode=WAL")
WAL 模式下,读写可以并发,但写操作仍然串行。
SQLite 的连接池配置和 MySQL 不同:
sqlDB, _ := db.DB()
sqlDB.SetMaxOpenConns(1)
对于文件数据库,MaxOpenConns 设为 1 可以避免 "database is locked" 错误。因为 SQLite 的锁是文件级别的,多个连接同时写入会冲突。
内存数据库可以开多个连接:
sqlDB.SetMaxOpenConns(10)
SQLite 是动态类型系统,字段类型比较灵活:
| Go 类型 | SQLite 类型 |
|---|---|
| int, uint | INTEGER |
| float64 | REAL |
| string | TEXT |
| bool | INTEGER (0/1) |
| time.Time | TEXT (ISO8601) |
| []byte | BLOB |
GORM 会自动处理类型转换。
SQLite 默认不启用外键约束,需要手动开启:
db.Exec("PRAGMA foreign_keys=ON")
或者每次连接时执行:
db, _ := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
db.Exec("PRAGMA foreign_keys=ON")
PRAGMA 是 SQLite 的配置指令,几个常用的:
db.Exec("PRAGMA journal_mode=WAL")
db.Exec("PRAGMA synchronous=NORMAL")
db.Exec("PRAGMA cache_size=-64000")
db.Exec("PRAGMA busy_timeout=5000")
journal_mode
日志模式。WAL 性能最好,推荐生产使用。
synchronous
同步级别。NORMAL 在性能和安全间平衡,FULL 最安全但慢。
cache_size
缓存大小。负数表示 KB,-64000 是 64MB。
busy_timeout
锁等待超时毫秒数。避免 "database is locked" 错误。
项目初期用 SQLite 快速开发,后期迁移到 PostgreSQL 或 MySQL:
import (
"gorm.io/driver/sqlite"
"gorm.io/driver/postgres"
)
var db *gorm.DB
func InitDB() {
if os.Getenv("ENV") == "production" {
dsn := "host=..."
db, _ = gorm.Open(postgres.Open(dsn), &gorm.Config{})
} else {
db, _ = gorm.Open(sqlite.Open("dev.db"), &gorm.Config{})
}
}
GORM 的抽象层让迁移变得简单,大部分代码不用改。
database is locked
并发写入冲突。解决方案:
no such table
表不存在。检查是否执行了自动迁移:
db.AutoMigrate(&User{})
CGO 编译失败
缺少 GCC 环境。Windows 上安装 MinGW 或 TDM-GCC,Linux 上安装 build-essential。
unable to open database file
文件路径不存在或无权限。确保目录存在且有写权限。
SQLite 简单、轻量、零配置,是开发测试和小型项目的利器。理解它的并发限制和适用场景,才能用好它。下一章看企业级的 SQL Server。