Go + GORM SQLite CURD完整示例
GORM 是Go最主流ORM,底层依然可以对接两种sqlite驱动:
github.com/mattn/go‑sqlite3(cgo)modernc.org/sqlite(纯Go无cgo,推荐,交叉编译友好)
GORM v2 版本。
1. 安装依赖
bash
go get gorm.io/gorm
# 纯Go sqlite驱动(无gcc,推荐)
go get gorm.io/driver/sqlite
gorm.io/driver/sqlite内部封装了modernc.org/sqlite,无需额外导入。
2. 完整代码 GORM CURD + 事务 + WAL优化
go
package main
import (
"fmt"
"log"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// User 模型,gorm自动映射表名 users
type User struct {
ID uint `gorm:"primaryKey;autoIncrement"`
Name string `gorm:"size:64;not null"`
Age int `gorm:"default:0"`
}
func main() {
// dsn 开启WAL模式,优化sqlite并发读写
dsn := "file:gorm_test.db?_journal=WAL&_synchronous=NORMAL&_timeout=5000"
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info), // 打印SQL日志
})
if err != nil {
log.Fatalf("数据库连接失败: %v", err)
}
// 获取底层sql.DB,设置连接池,sqlite固定1个连接
sqlDB, err := db.DB()
if err != nil {
log.Fatal(err)
}
defer sqlDB.Close()
sqlDB.SetMaxOpenConns(1)
sqlDB.SetMaxIdleConns(1)
// 自动建表,表不存在创建;字段变更不会删除旧字段
err = db.AutoMigrate(&User{})
if err != nil {
log.Fatalf("迁移建表失败: %v", err)
}
// ========== C 创建 ==========
u1 := User{Name: "张三", Age: 22}
err = db.Create(&u1).Error
if err != nil {
log.Fatal(err)
}
fmt.Printf("创建成功,ID=%d\n", u1.ID)
// 批量创建
batchUsers := []User{
{Name: "李四", Age: 20},
{Name: "王五", Age: 24},
}
err = db.Create(&batchUsers).Error
if err != nil {
log.Fatal(err)
}
// ========== R 查询 ==========
// 根据ID查单条
var u User
err = db.First(&u, u1.ID).Error
if err != nil {
log.Fatal(err)
}
fmt.Printf("查询单条:%+v\n", u)
// 条件查询
var findU User
err = db.Where("name = ?", "张三").First(&findU).Error
if err != nil {
log.Fatal(err)
}
// 查询全部列表
var list []User
err = db.Find(&list).Error
if err != nil {
log.Fatal(err)
}
fmt.Printf("列表:%+v\n", list)
// 分页查询
var pageList []User
offset := 0
limit := 2
err = db.Offset(offset).Limit(limit).Find(&pageList).Error
if err != nil {
log.Fatal(err)
}
// ========== U 更新 ==========
// 更新单个字段
err = db.Model(&u).Where("id = ?", u.ID).Update("age", 25).Error
if err != nil {
log.Fatal(err)
}
// 更新多个字段 map方式
err = db.Model(&User{}).Where("id = ?", u.ID).Updates(map[string]any{
"name": "张三改名",
"age": 26,
}).Error
if err != nil {
log.Fatal(err)
}
// ========== D 删除 ==========
// 物理删除(真正删掉记录)
err = db.Delete(&User{}, u.ID).Error
if err != nil {
log.Fatal(err)
}
// ========== 事务 ==========
err = demoTx(db)
if err != nil {
log.Println("事务失败:", err)
}
}
// demoTx GORM事务示例
func demoTx(db *gorm.DB) error {
return db.Transaction(func(tx *gorm.DB) error {
// 在tx内执行所有数据库操作
if err := tx.Create(&User{Name: "事务A", Age: 18}).Error; err != nil {
return err // 返回错误自动回滚
}
if err := tx.Create(&User{Name: "事务B", Age: 19}).Error; err != nil {
return err
}
// 返回nil自动提交
return nil
})
}GORM SQLite关键要点
- AutoMigrate:自动迁移,适合开发环境;生产环境建议手写SQL迁移脚本,不要依赖AutoMigrate。
- sqlite驱动
gorm.io/driver/sqlite底层用modernc.org/sqlite,纯Go无cgo,交叉编译非常方便。 - DSN参数建议固定开启WAL:
_journal=WAL&_synchronous=NORMAL,大幅提升并发读写性能。 - 连接池:SQLite文件锁不支持多写并发,
SetMaxOpenConns=1是最优配置。 - GORM的
Delete默认物理删除;想要软删除,模型嵌入gorm.Model,自带DeletedAt字段。
go
type User struct {
gorm.Model
Name string
Age int
}嵌入后调用db.Delete(&user)不会真正删除,只是填充删除时间;查询会自动过滤已软删除数据。
简易DAO封装(工程化模板)
实际项目不会把db操作写main函数,封装DAO层:
go
package dao
import (
"gorm.io/gorm"
)
type UserDao struct {
db *gorm.DB
}
func NewUserDao(db *gorm.DB) *UserDao {
return &UserDao{db: db}
}
type User struct {
ID uint `gorm:"primaryKey;autoIncrement"`
Name string `gorm:"size:64;not null"`
Age int `gorm:"default:0"`
}
// Create 创建
func (d *UserDao) Create(u *User) error {
return d.db.Create(u).Error
}
// GetByID 根据id查询
func (d *UserDao) GetByID(id uint) (*User, error) {
var u User
err := d.db.First(&u, id).Error
if err != nil {
return nil, err
}
return &u, nil
}
// List 查询全部
func (d *UserDao) List() ([]User, error) {
var list []User
err := d.db.Find(&list).Error
return list, err
}
// Update 更新
func (d *UserDao) Update(id uint, data map[string]any) error {
return d.db.Model(&User{}).Where("id=?", id).Updates(data).Error
}
// Delete 删除
func (d *UserDao) Delete(id uint) error {
return d.db.Delete(&User{}, id).Error
}使用DAO
go
// 获取db实例后
userDao := dao.NewUserDao(db)
_ = userDao.Create(&dao.User{Name:"test",Age:30})两种驱动对比
| 驱动 | cgo | 编译 | 适用场景 |
|---|---|---|---|
mattn/go‑sqlite3 | 需要gcc | 不能交叉编译 | 本地开发 |
modernc.org/sqlite(gorm.io/driver/sqlite) | 无cgo | 支持交叉编译 | 生产打包部署,推荐 |