Skip to content

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关键要点

  1. AutoMigrate:自动迁移,适合开发环境;生产环境建议手写SQL迁移脚本,不要依赖AutoMigrate。
  2. sqlite驱动gorm.io/driver/sqlite底层用modernc.org/sqlite纯Go无cgo,交叉编译非常方便。
  3. DSN参数建议固定开启WAL:_journal=WAL&_synchronous=NORMAL,大幅提升并发读写性能。
  4. 连接池:SQLite文件锁不支持多写并发,SetMaxOpenConns=1是最优配置。
  5. 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支持交叉编译生产打包部署,推荐