Golang原生database-sql 包的纯 Go SQLite 驱动程序使用
仓库地址: https://github.com/glebarez/go-sqlite
这是 Golang 原生 database/sql 包的纯 Go SQLite 驱动程序。 该驱动程序本身嵌入了基于 Go 的 SQLite 实现(因此,不需要单独安装 SQLite)
使用示例
go
package bootstrap
import (
"database/sql"
_ "github.com/glebarez/go-sqlite"
"go.uber.org/zap"
"log"
"low-file/src/global"
"os"
"path/filepath"
)
var createTableStatements = []string{
// 文件记录表
`
CREATE TABLE IF NOT EXISTS file_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
file_name TEXT NOT NULL,
file_path TEXT NOT NULL,
file_size INTEGER NOT NULL,
create_time INTEGER NOT NULL
)
`,
}
func initSqlite() {
// 获取数据库文件路径(分离目录和文件名)
dataDir := filepath.Join(global.BasePath, "storage/data") // 目录路径
dbFile := filepath.Join(dataDir, "low-file.db") // 文件路径
// 创建数据目录(仅创建目录部分)
if err := os.MkdirAll(dataDir, 0755); err != nil {
log.Fatalf("sqlite目录创建失败: %v (路径: %s)", err, dataDir)
}
// 验证目录权限(可选)
if fileInfo, err := os.Stat(dataDir); err != nil {
log.Fatalf("sqlite目录访问失败: %v (路径: %s)", err, dataDir)
} else if !fileInfo.IsDir() {
log.Fatalf("sqlite路径不是目录: %s", dataDir)
} else if fileInfo.Mode().Perm()&0200 == 0 {
log.Fatalf("sqlite目录不可写: %s (权限: %s)", dataDir, fileInfo.Mode().String())
}
// 初始化数据库连接
db, err := sql.Open("sqlite", dbFile+"?_foreign_keys=1&_journal_mode=WAL")
if err != nil {
log.Fatal("sqlite数据库连接失败:", err)
}
// 配置连接池(SQLite推荐设置)
db.SetMaxOpenConns(1) // 重要!避免数据库锁定
db.SetMaxIdleConns(1)
// 验证连接
if err := db.Ping(); err != nil {
log.Fatal("sqlite数据库连接不可用:", err)
}
global.SQLite = db
// 初始化表
initTable()
// 记录版本信息
var version string
if err := global.SQLite.QueryRow("SELECT sqlite_version()").Scan(&version); err != nil {
global.Logger.Error("获取SQLite版本失败", zap.Error(err))
} else {
global.Logger.Info("SQLite初始化完成",
zap.String("version", version),
zap.String("path", dbFile))
}
}
func initTable() {
for _, val := range createTableStatements {
_, err := global.SQLite.Exec(val)
if err != nil {
log.Fatal("初始化表失败:", err)
}
}
}分页查询示例
go
package handlers
import (
"github.com/gin-gonic/gin"
"low-file/src/common/model"
"low-file/src/global"
"math"
)
type FileRecordListQueryParam struct {
model.PageQuery
}
func FileRecordList(c *gin.Context) {
resHandler, _ := global.GetLoggerAndResponseHandler(c)
// 1. 参数绑定与校验
var pageQuery FileRecordListQueryParam
if err := c.ShouldBind(&pageQuery); err != nil {
global.ResFail(resHandler.WithMsg("查询参数绑定失败").WithError(err))
return
}
// 参数默认值设置
if pageQuery.PageNum < 1 {
pageQuery.PageNum = 1
}
if pageQuery.PageSize <= 0 || pageQuery.PageSize > 100 {
pageQuery.PageSize = 10
}
// 2. 查询总数(带错误处理)
var count int64
err := global.SQLite.QueryRow(
`SELECT COUNT(*) FROM file_records`,
).Scan(&count)
if err != nil {
global.ResFail(resHandler.WithMsg("总数查询失败").WithError(err))
return
}
// 快速返回空结果
if count == 0 {
global.ResOk(resHandler.WithData(gin.H{
"rows": []interface{}{},
"total": 0,
}))
return
}
// 3. 分页查询(添加 ORDER BY 保证顺序)
offset := (pageQuery.PageNum - 1) * pageQuery.PageSize
rows, err := global.SQLite.Query(
`SELECT * FROM file_records
ORDER BY create_time DESC
LIMIT ? OFFSET ?`,
pageQuery.PageSize, offset,
)
if err != nil {
global.ResFail(resHandler.WithMsg("分页查询失败").WithError(err))
return
}
defer rows.Close() // 确保关闭结果集
// 4. 数据解析
var records []model.FileRecord
for rows.Next() {
var s model.FileRecord
if err := rows.Scan(&s.Id, &s.FileName, &s.FilePath, &s.FileSize, &s.CreateTime); err != nil {
global.ResFail(resHandler.WithMsg("解析记录行失败").WithError(err))
return
}
records = append(records, s)
}
// 5. 检查遍历错误
if err := rows.Err(); err != nil {
global.ResFail(resHandler.WithMsg("结果集遍历错误").WithError(err))
return
}
// 6. 返回完整分页信息
_ = int(math.Ceil(float64(count) / float64(pageQuery.PageSize)))
global.ResOk(resHandler.WithData(gin.H{
"rows": records,
"total": count,
}))
}