badger 作本地配置库需正确设置路径、事务和关闭:必须显式指定绝对路径的 dir 和 valuedir 并创建目录,写操作用 db.newtransaction(true) 并调 commit(),读操作用 item.valuecopy(nil) 拷贝值,关库前务必调 db.close()。

Badger 能直接当无服务本地配置库用,但默认开箱即用的写法大概率导致重启后配置丢失、读出来是空、或进程退出时报 manifest has unsupported version —— 根子在路径、事务和关闭三处没设对。
打开数据库必须显式指定 Dir 和 ValueDir
Badger 不会帮你创建父目录,也不接受相对路径或空字符串。传 badger.DefaultOptions("") 或只设 Dir 不设 ValueDir,它会静默用临时目录,进程一退数据就清空。
- 务必用
filepath.Abs("./config")转成绝对路径,再os.MkdirAll(dir, 0755)显式建好目录(Dir和ValueDir都要) - 若想复用同一目录,必须显式赋值:
opt := badger.DefaultOptions("/path/to/config").WithValueDir("/path/to/config") - 别依赖旧版行为:v3 默认不再自动复用
Dir当ValueDir,漏设就 panic
存配置必须走写事务并调 Commit()
Badger 没有 db.Put() 这种直写接口。所有写操作都得包在 db.NewTransaction(true) 里,否则要么 panic,要么“看似成功实则没落盘”。
- 错例:
txn := db.NewTransaction(false)后调txn.Set()→ 报cannot perform write on read-only transaction - 更隐蔽的坑:忘了
txn.Commit(),程序不报错,但下次启动就读不到刚写的配置 - 推荐写法:
defer txn.Discard()开头,成功时用txn.Commit()替换;或直接用db.Update(),它自动 commit/discard
读配置必须用 item.ValueCopy(nil) 拷贝值
item.Value() 返回的是事务内内存切片,事务一结束,这块内存可能被复用或释放。直接拿它转 string 或 json.Unmarshal,轻则读到脏数据,重则 panic。
- 安全读法:
val, err := item.ValueCopy(nil),返回独立字节切片,生命周期脱离事务 - 结构体配置要反序列化:
json.Unmarshal(val, &cfg),注意val是只读的,别往里写 - 别传
item.Value()给json.Unmarshal或string()—— 看似能跑,但上线后某次 GC 就崩
关库前必须调 db.Close(),且不能重复
Badger 用 mmap 和后台 goroutine 管理文件,不关库就退出,value log 容易损坏,下次启动直接卡在 checksum mismatch 或 manifest has unsupported version。
- 务必在
main()结束前、或收到SIGINT时调db.Close() - 重复调
db.Close()会 panic,建议用sync.Once包一层,或确保只 defer 一次 - 别把
db当全局变量反复Open()/Close()—— 同一目录不支持多实例
最易被忽略的是:ValueCopy(nil) 不是可选优化,是内存安全红线;db.Close() 不是优雅收尾,是防止下次启动失败的必要动作。这两点不做到,配置库就不是“极简”,而是“极脆”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











