Go项目的CRUD
开发项目时,如果用到数据库,难免需要CRUD,但是在go项目中如何进行CRUD呢?这里分享下我的经验。

开发项目难免需要CRUD,但是在go项目中如何进行CRUD呢?这里分享下我的经验。

下面以一个项目中的一个system模块为例,文件组织如下:

├── system
│   ├── dao
│   │   ├── dao.go
│   │   ├── dao_test.go
│   │   └── user.go
│   ├── dao_mock.go
│   ├── dao.go
│   ├── model
│   │   └── user.go
│   ├── service
│   │   ├── service.go
│   │   ├── service_test.go
│   │   ├── user_test.go
│   │   └── user.go
│   ├── service_mock.go
│   └── service.go
  • /system: 模块,一个中大型项目有多个模块,例如:system、product、trade等
  • /dao: 这个目录存放数据库操作相关的文件,例如:user.go、role.go、menu.go等
  • /dao/dao.go: 定义了Dao结构体和实例化方法
  • /dao/user.go:操作user表相关的方法
  • /model:model目录存放system模块需要用到的所有结构体
  • /model/user.go: 用户数据相关结构体,例如:表Schema结构体、FindUserFilter结构体、user对外的参数结构体等
  • /dao.go: 定义数据库操作对外的接口

这里只讲数据库相关,不涉及service.go、service/等

一、dao.go

dao.go 定义了DAO接口,所有的数据库操作都需要先在DAO中定义。

dao.go 的顶部使用go:generate 生成到 dao_mock.go,这样service中写单元测试时,可以不需要连接数据库。

//go:generate mockgen -source $GOFILE -destination ./dao_mock.go -package $GOPACKAGE
package system

import (
	"context"

	"xxx/internal/module/system/model"
)

type DAO interface {
	CreateUser(ctx context.Context, m *model.User) error
	UpdateUsers(ctx context.Context, filter *model.FindUserFilter, update map[string]any) (int64, error)
	UpdateUser(ctx context.Context, m *model.User, update map[string]any) error
	CountUsers(ctx context.Context, filter *model.FindUserFilter) (int64, error)
	FindUsers(ctx context.Context, filter *model.FindUserFilter) ([]*model.User, error)
	FindUserByID(ctx context.Context, id int64) (*model.User, error)
	FindUser(ctx context.Context, filter *model.FindUserFilter) (*model.User, error)
	DeleteUsers(ctx context.Context, filter *model.FindUserFilter) error
}

二、model/user.go

package model

import (
	"strings"

	"github.com/samber/lo"

	"xxx/internal/pkg/db"
)

type User struct {
	db.Model

	Username string
	Nickname string
	Phone    string
	Email    string
	Gender   string
	Roles    string
	Password string
	Status   UserStatus
}

func (User) TableName() string {
	return TableUsers
}

type FindUserFilter struct {
	db.BaseFilter

	ID       db.F[int64]
	IDs      db.F[[]int64] `gorm:"column:id"`
	Username db.F[string]
	Phone    db.F[string]
	Nickname db.F[string]
	Gender   db.F[string]
	Email    db.F[string]
	Status   db.F[UserStatus]
}

type CreateUserRequest {
  // TODO
}
type UpdateUserRequest {
  // TODO
}

其中 User结构体对应数据库的User Schema,所有的字段都定义在里面。

而FindUserFilter结构体是FindUser、UpdateUser、DeleteUser时需要传递的参数例如

s.dao.FindUser(ctx, model.FinUserFilter{
	Username: db.Eq("zhangsan"),
	Status: db.Eq("disable"),
	Gender: db.Ne("femal")
})

三、/dao

1、 dao/dao.go

package dao

import (
	"github.com/samber/do/v2"

	"xxx/internal/module/system"
)

type Dao struct {
}

func New(i do.Injector) (system.DAO, error) {
	return &Dao{}, nil
}

dao.go 定义了Dao结构体,并提供了 依赖注入的New方法。

2 dao/user.go

package dao

import (
	"context"

	"xxx/internal/module/system/model"
	"xxx/internal/pkg/db"
)

func (d *Dao) CreateUser(ctx context.Context, m *model.User) error {
	return db.GetDB(ctx).Create(m).Error
}

func (d *Dao) UpdateUsers(ctx context.Context, filter *model.FindUserFilter, update map[string]any) (int64, error) {
	return db.Updates(ctx, &model.User{}, filter, update)
}

func (d *Dao) UpdateUser(ctx context.Context, m *model.User, update map[string]any) error {
	return db.Update(ctx, m, update)
}

func (d *Dao) CountUsers(ctx context.Context, f *model.FindUserFilter) (total int64, err error) {
	return db.Count(ctx, &model.User{}, f)
}

func (d *Dao) FindUsers(ctx context.Context, f *model.FindUserFilter) (ms []*model.User, err error) {
	err = db.Find(ctx, f, &ms)
	return
}

func (d *Dao) FindUser(ctx context.Context, f *model.FindUserFilter) (*model.User, error) {
	var m model.User
	if err := db.FindOne(ctx, f, &m); err != nil {
		return nil, err
	} else {
		return &m, nil
	}
}

func (d *Dao) FindUserByID(ctx context.Context, id int64) (m *model.User, err error) {
	return d.FindUser(ctx, &model.FindUserFilter{ID: db.Eq(id)})
}

func (d *Dao) DeleteUsers(ctx context.Context, filter *model.FindUserFilter) error {
	_, err := db.Delete(ctx, &model.User{}, filter)
	return err
}

最后修改于 2025-06-09

此篇文章的评论功能已经停用。