Skip to content

Latest commit

 

History

History
408 lines (303 loc) · 10.6 KB

File metadata and controls

408 lines (303 loc) · 10.6 KB

CRUD 操作详解

本文档详细介绍 daog 提供的增删改查操作。

概述

daog 提供两种调用方式:

  1. 函数方式: 调用 daog.GetById(tc, id, meta) 等函数,需要传递 TableMeta
  2. QuickDao 方式: 调用 dal.UserInfoDao.GetById(tc, id),无需传递 TableMeta

两种方式功能完全相同,本文档使用 QuickDao 方式演示。

Insert 插入

单条插入

import (
    "github.com/rolandhe/daog"
    txrequest "github.com/rolandhe/daog/tx"
    "github.com/rolandhe/daog/ttypes"
    "your/project/dal"
)

func createUser() (*dal.UserInfo, error) {
    return daog.AutoTransWithResult(func() (*daog.TransContext, error) {
        return daog.NewTransContext(datasource, txrequest.RequestWrite, "trace-id")
    }, func(tc *daog.TransContext) (*dal.UserInfo, error) {
        user := &dal.UserInfo{
            Name:     "张三",
            CreateAt: ttypes.NormalDatetime(time.Now()),
        }

        // 插入并返回影响行数
        affectedRows, err := dal.UserInfoDao.Insert(tc, user)
        if err != nil {
            return nil, err
        }

        // 自增 ID 已自动回填到 user.Id
        fmt.Printf("插入成功,ID: %d, 影响行数: %d\n", user.Id, affectedRows)
        return user, nil
    })
}

关键点:

  • 自增 ID 列在插入时会被自动排除
  • 插入成功后,自增 ID 会自动回填到结构体的对应字段

时间戳自动填充

如果表的 TableMeta.StampColumns 配置了时间戳列,daog 会在插入时自动填充当前时间:

// 在 -ext.go 文件的 init 函数中配置
func init() {
    // 1 表示插入时填充,2 表示更新时填充,3 表示插入和更新都填充
    UserInfoMeta.StampColumns = map[string]int{
        "create_at": 1, // 仅插入时填充
        "modify_at": 3, // 插入和更新都填充
    }
}

Query 查询

GetById - 根据主键查询

// 查询所有字段
user, err := dal.UserInfoDao.GetById(tc, 100)

// 查询指定字段(视图)
user, err := dal.UserInfoDao.GetById(tc, 100,
    dal.UserInfoFields.Id,
    dal.UserInfoFields.Name)

GetByIds - 根据多个主键查询

ids := []int64{1, 2, 3, 4, 5}
users, err := dal.UserInfoDao.GetByIds(tc, ids)

// 使用视图
users, err := dal.UserInfoDao.GetByIds(tc, ids,
    dal.UserInfoFields.Id,
    dal.UserInfoFields.Name)

GetAll - 查询所有数据

// 查询所有记录
users, err := dal.UserInfoDao.GetAll(tc)

// 查询指定字段
users, err := dal.UserInfoDao.GetAll(tc,
    dal.UserInfoFields.Id,
    dal.UserInfoFields.Name)

QueryOneMatcher - 条件查询单条

matcher := daog.NewMatcher().
    Eq(dal.UserInfoFields.Name, "张三")

user, err := dal.UserInfoDao.QueryOneMatcher(tc, matcher)
if user == nil {
    // 未找到记录
}

QueryListMatcher - 条件查询多条

matcher := daog.NewMatcher().
    Eq(dal.UserInfoFields.Status, 1).
    Gt(dal.UserInfoFields.Age, 18)

// 基本查询
users, err := dal.UserInfoDao.QueryListMatcher(tc, matcher)

// 带排序
users, err := dal.UserInfoDao.QueryListMatcher(tc, matcher,
    daog.NewDescOrder(dal.UserInfoFields.CreateAt))

// 指定查询字段
users, err := dal.UserInfoDao.QueryListMatcherWithViewColumns(tc, matcher,
    []string{dal.UserInfoFields.Id, dal.UserInfoFields.Name})

QueryPageListMatcher - 分页查询

matcher := daog.NewMatcher().Eq(dal.UserInfoFields.Status, 1)

// 创建分页对象:每页 10 条,查询第 1 页
pager := daog.NewPager(10, 1)

// 排序条件
order := daog.NewDescOrder(dal.UserInfoFields.CreateAt)

users, err := dal.UserInfoDao.QueryPageListMatcher(tc, matcher, pager, order)

使用 View 对象

除了使用字符串数组指定查询列,还可以使用 View 对象:

// 包含指定字段
view := daog.NewView([]string{
    dal.UserInfoFields.Id,
    dal.UserInfoFields.Name,
})
users, err := dal.UserInfoDao.GetAllWithViewObj(tc, view)

// 排除指定字段
excludeView := daog.NewExcludeView([]string{
    dal.UserInfoFields.Content,  // 排除大字段
    dal.UserInfoFields.BinData,
})
users, err := dal.UserInfoDao.GetAllWithViewObj(tc, excludeView)

GetByIdForUpdate - FOR UPDATE 查询

用于悲观锁场景,查询时锁定行:

// 标准 FOR UPDATE
user, err := dal.UserInfoDao.GetByIdForUpdate(tc, 100, false)

// FOR UPDATE SKIP LOCKED(跳过已锁定的行)
user, err := dal.UserInfoDao.GetByIdForUpdate(tc, 100, true)

// 条件查询 + FOR UPDATE
matcher := daog.NewMatcher().Eq(dal.UserInfoFields.Status, 1)
users, err := dal.UserInfoDao.QueryListMatcherForUpdate(tc, matcher, false)

注意: FOR UPDATE 必须在写事务 (txrequest.RequestWrite) 中使用。

批量处理 - BatchHandler

当需要处理大量数据时,使用批量处理可以避免内存溢出:

matcher := daog.NewMatcher().Eq(dal.UserInfoFields.Status, 1)

// 批量处理:每次处理 100 条,总共处理 10000 条
err := dal.UserInfoDao.QueryListMatcherByBatchHandle(tc, matcher,
    10000,  // totalLimit: 总数上限,0 表示无限制
    100,    // batchSize: 每批大小
    func(batch []*dal.UserInfo) error {
        // 处理当前批次的数据
        for _, user := range batch {
            // 业务处理...
        }
        return nil
    },
    daog.NewOrder(dal.UserInfoFields.Id), // 排序
)

Count - 统计数量

matcher := daog.NewMatcher().
    Eq(dal.UserInfoFields.Status, 1).
    Gt(dal.UserInfoFields.Age, 18)

count, err := dal.UserInfoDao.Count(tc, matcher)
fmt.Printf("符合条件的记录数: %d\n", count)

Update 更新

整体更新

更新整个对象,根据主键匹配:

func updateUser(id int64) error {
    return daog.AutoTrans(func() (*daog.TransContext, error) {
        return daog.NewTransContext(datasource, txrequest.RequestWrite, "trace-id")
    }, func(tc *daog.TransContext) error {
        // 先查询
        user, err := dal.UserInfoDao.GetById(tc, id)
        if err != nil {
            return err
        }
        if user == nil {
            return errors.New("user not found")
        }

        // 修改字段
        user.Name = "李四"
        user.ModifyAt = *ttypes.FromDatetime(time.Now())

        // 更新(根据主键 Id 匹配)
        affectedRows, err := dal.UserInfoDao.Update(tc, user)
        return err
    })
}

批量整体更新

users := []*dal.UserInfo{user1, user2, user3}
affectedRows, err := dal.UserInfoDao.UpdateList(tc, users)

注意: 在非事务模式 (txrequest.RequestNone) 下,如果某条更新失败,之前的更新不会回滚。

UpdateById - 使用 Modifier 更新

使用 Modifier 只更新指定字段:

modifier := daog.NewModifier().
    Add(dal.UserInfoFields.Name, "王五").
    Add(dal.UserInfoFields.ModifyAt, ttypes.NormalDatetime(time.Now()))

affectedRows, err := dal.UserInfoDao.UpdateById(tc, modifier, 100)

UpdateByIds - 批量更新

modifier := daog.NewModifier().
    Add(dal.UserInfoFields.Status, 0)

ids := []int64{1, 2, 3, 4, 5}
affectedRows, err := dal.UserInfoDao.UpdateByIds(tc, modifier, ids)

UpdateByModifier - 条件更新

modifier := daog.NewModifier().
    Add(dal.UserInfoFields.Status, 0)

matcher := daog.NewMatcher().
    Eq(dal.UserInfoFields.Status, 1).
    Lt(dal.UserInfoFields.CreateAt, expiredTime)

affectedRows, err := dal.UserInfoDao.UpdateByModifier(tc, modifier, matcher)

Modifier 高级用法

modifier := daog.NewModifier().
    // 普通赋值: SET name = ?
    Add(dal.UserInfoFields.Name, "新名字").

    // 自增: SET count = count + ?
    SelfAdd(dal.UserInfoFields.ViewCount, 1).

    // 自减: SET stock = stock - ?
    SelfMinus(dal.UserInfoFields.Stock, 1)

Delete 删除

DeleteById - 根据主键删除

affectedRows, err := dal.UserInfoDao.DeleteById(tc, 100)

DeleteByIds - 批量删除

ids := []int64{1, 2, 3, 4, 5}
affectedRows, err := dal.UserInfoDao.DeleteByIds(tc, ids)

DeleteByMatcher - 条件删除

matcher := daog.NewMatcher().
    Eq(dal.UserInfoFields.Status, 0).
    Lt(dal.UserInfoFields.CreateAt, expiredTime)

affectedRows, err := dal.UserInfoDao.DeleteByMatcher(tc, matcher)

安全限制: DeleteByMatcher 必须指定有效条件,不允许删除全表数据。如果 Matcher 为空或条件为空,操作会被拒绝。

原生 SQL 执行

ExecRawSQL - 执行原生写操作

sql := "UPDATE user_info SET status = ? WHERE id = ? AND status = ?"
affectedRows, err := dal.UserInfoDao.ExecRawSQL(tc, sql, 1, 100, 0)

ExecInsertWithAutoId - 执行原生插入并获取自增 ID

sql := "INSERT INTO user_info(name, create_at) VALUES(?, ?)"
lastInsertId, err := dal.UserInfoDao.ExecInsertWithAutoId(tc, sql,
    "张三", time.Now())

QueryRawSQL - 执行原生查询

type UserSummary struct {
    Id    int64
    Name  string
    Count int64
}

sql := `SELECT u.id, u.name, COUNT(o.id) as count
        FROM user_info u
        LEFT JOIN orders o ON u.id = o.user_id
        WHERE u.status = ?
        GROUP BY u.id`

// 提供字段映射函数
extract := func(ins *UserSummary) []any {
    return []any{&ins.Id, &ins.Name, &ins.Count}
}

results, err := daog.QueryRawSQL(tc, extract, sql, 1)

QueryRawSQLByBatchHandle - 原生查询批量处理

sql := "SELECT id, name, email FROM user_info WHERE status = ?"

extract := func(ins *dal.UserInfo) []any {
    return []any{&ins.Id, &ins.Name, &ins.Email}
}

err := daog.QueryRawSQLByBatchHandle(tc, 100, func(batch []*dal.UserInfo) error {
    for _, user := range batch {
        // 处理数据...
    }
    return nil
}, extract, sql, 1)

函数方式 vs QuickDao 方式对照

操作 函数方式 QuickDao 方式
插入 daog.Insert(tc, user, dal.UserInfoMeta) dal.UserInfoDao.Insert(tc, user)
主键查询 daog.GetById(tc, id, dal.UserInfoMeta) dal.UserInfoDao.GetById(tc, id)
条件查询 daog.QueryListMatcher(tc, m, dal.UserInfoMeta) dal.UserInfoDao.QueryListMatcher(tc, m)
整体更新 daog.Update(tc, user, dal.UserInfoMeta) dal.UserInfoDao.Update(tc, user)
条件更新 daog.UpdateByModifier(tc, mod, m, dal.UserInfoMeta) dal.UserInfoDao.UpdateByModifier(tc, mod, m)
删除 daog.DeleteById(tc, id, dal.UserInfoMeta) dal.UserInfoDao.DeleteById(tc, id)
统计 daog.Count(tc, m, dal.UserInfoMeta) dal.UserInfoDao.Count(tc, m)

相关文档