sqlite是桌面语言学习配置的合理选择,因其无需独立服务进程、单文件存储且具备acid保障,比mysql/postgresql更轻量,又比json更可靠;go中需配置wal模式、busy_timeout、sync=off,并设maxopenconns=1以避免并发写锁。

为什么 SQLite 是桌面语言学习配置的合理选择
SQLite 不需要独立服务进程、单文件存储、ACID 保证足够用,对初学 Go 的人来说,比启动 MySQL 或 PostgreSQL 更轻量,也比纯 JSON 文件更可靠——尤其当多个 goroutine 同时读写配置时。sql.Open("sqlite3", "config.db") 一行就能连上,但默认不启用 WAL 模式,高并发写入容易卡住或报 database is locked。
Go 连接 SQLite 必须加的参数和初始化步骤
直接 sql.Open("sqlite3", "config.db") 很危险:默认使用 legacy locking mode,且没设连接池。实际要用带参数的 DSN:
db, err := sql.Open("sqlite3", "config.db?_journal_mode=WAL&_busy_timeout=5000&_sync=OFF")
接着必须显式调用 db.Ping() 和设置连接池:
-
db.SetMaxOpenConns(1):SQLite 不支持多写并发,设为 1 避免竞争 -
db.SetMaxIdleConns(1):防止空闲连接堆积导致锁未释放 - 首次运行时用
db.Exec("CREATE TABLE IF NOT EXISTS config (key TEXT PRIMARY KEY, value TEXT NOT NULL)")
读写配置时如何避免事务和类型陷阱
SQLite 没有原生布尔或整型存储,存 true 实际是字符串 "true";用 SELECT value FROM config WHERE key = ? 查出来永远是 string,不能直接断言为 bool 或 int。正确做法是封装读写函数:
func SetConfig(db *sql.DB, key string, value interface{}) error {
v := fmt.Sprintf("%v", value)
_, err := db.Exec("INSERT OR REPLACE INTO config(key, value) VALUES(?, ?)", key, v)
return err
}
func GetConfigString(db *sql.DB, key string, def string) string {
var v string
err := db.QueryRow("SELECT value FROM config WHERE key = ?", key).Scan(&v)
if err != nil {
return def
}
return v
}
如果要存结构体,别序列化进单字段——拆成多列,或用 json.Marshal 后存字符串,但记得读取后手动 json.Unmarshal,否则类型丢失。
Windows 下路径和权限导致的常见失败
在 Windows 上,config.db 默认创建在当前工作目录,而 IDE(如 VS Code)常以项目根目录为工作目录,打包成 exe 后可能变成 C:\Windows\System32 —— 导致写入失败或配置丢失。必须明确指定路径:
- 用
os.UserHomeDir()+filepath.Join(".mylang", "config.db")定位到用户目录 - 创建前先
os.MkdirAll(filepath.Dir(dbPath), 0755) - 避免用相对路径如
"./config.db",它依赖os.Getwd(),不可控
SQLite 文件被其他进程(比如另一个正在调试的 Go 程序实例)独占时,database is locked 错误不会自动重试,得靠 _busy_timeout=5000 参数撑住,而不是靠代码循环 retry。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











