Coze源码分析-资源库-创建数据库-后端源码-应用/领域/数据访问层

3. 应用服务层

3.1 数据库应用服务

文件位置 : backend/application/memory/database.go

go 复制代码
func (d *DatabaseApplicationService) AddDatabase(ctx context.Context, req *table.AddDatabaseRequest) (*table.SingleDatabaseResponse, error) {
    // 1. 用户身份验证
    uid := ctxutil.GetUIDFromCtx(ctx)
    if uid == nil {
        return nil, errorx.New(errno.ErrMemoryPermissionCode, errorx.KV("msg", "session required"))
    }
    if *uid != req.CreatorID {
        return nil, errorx.New(errno.ErrMemoryPermissionCode, errorx.KV("msg", "creator id is invalid"))
    }

    // 2. 表名验证
    if req.GetTableName() == "database" {
        return nil, errorx.New(errno.ErrMemoryDatabaseNameInvalid)
    }

    // 3. 空间权限验证
    spaces, err := crossuser.DefaultSVC().GetUserSpaceList(ctx, *uid)
    if err != nil {
        return nil, err
    }
    if len(spaces) == 0 || spaces[0].ID != req.SpaceID {
        return nil, errorx.New(errno.ErrMemoryPermissionCode, errorx.KV("msg", "space id is invalid"))
    }

    // 4. 调用领域服务创建数据库
    res, err := d.DomainSVC.CreateDatabase(ctx, convertAddDatabase(req))
    if err != nil {
        return nil, err
    }

    // 5. 发布资源创建事件
    databaseRes := res.Database
    var ptrAppID *int64
    if databaseRes.AppID != 0 {
        ptrAppID = ptr.Of(databaseRes.AppID)
    }
    err = d.eventbus.PublishResources(ctx, &searchEntity.ResourceDomainEvent{
        OpType: searchEntity.Created,
        Resource: &searchEntity.ResourceDocument{
            ResType:       resCommon.ResType_Database,
            ResID:         databaseRes.ID,
            Name:          &databaseRes.TableName,
            APPID:         ptrAppID,
            SpaceID:       &databaseRes.SpaceID,
            OwnerID:       &databaseRes.CreatorID,
            PublishStatus: ptr.Of(resCommon.PublishStatus_Published),
            CreateTimeMS:  ptr.Of(databaseRes.CreatedAtMs),
            UpdateTimeMS:  ptr.Of(databaseRes.UpdatedAtMs),
        },
    })
    if err != nil {
        return nil, fmt.Errorf("publish resource failed, err=%w", err)
    }

    // 6. 转换并返回结果
    return ConvertDatabaseRes(databaseRes), nil
}

3.2 应用服务特点

数据库应用服务的主要特点:

  • 多重身份验证: 验证会话和创建者ID一致性
  • 表名验证: 防止使用保留字"database"作为表名
  • 空间权限验证: 确保用户有权限在指定空间创建数据库
  • 请求转换: 通过convertAddDatabase函数将API层请求转换为领域层请求
  • 事件发布: 创建成功后发布资源创建事件,用于更新搜索索引
  • 结果转换: 通过ConvertDatabaseRes函数将领域层结果转换为API层响应

3.3 事件驱动架构

数据库创建完成后,系统会发布资源创建事件:

go 复制代码
// 发布创建事件
err = k.eventBus.PublishResources(ctx, &resourceEntity.ResourceDomainEvent{
    OpType: resourceEntity.Created,
    Resource: &resourceEntity.ResourceDocument{
        ResType:       resource.ResType_Database,
        ResID:         domainResp.DatabaseID,
        Name:          ptr.Of(req.Name),
        ResSubType:    ptr.Of(int32(req.FormatType)),
        SpaceID:       ptr.Of(req.SpaceID),
        APPID:         ptrAppID,
        OwnerID:       ptr.Of(*uid),
        PublishStatus: ptr.Of(resource.PublishStatus_Published),
        PublishTimeMS: ptr.Of(domainResp.CreatedAtMs),
        CreateTimeMS:  ptr.Of(domainResp.CreatedAtMs),
        UpdateTimeMS:  ptr.Of(domainResp.CreatedAtMs),
    },
})

这个事件会被搜索服务监听,用于更新搜索索引,确保新创建的知识库能够被搜索到。

4. 领域服务层

4.1 数据库领域服务

文件位置 : backend/domain/memory/database/service/database.go

数据库领域服务接口定义:

go 复制代码
type Database interface {
    CreateDatabase(ctx context.Context, req *CreateDatabaseRequest) (*CreateDatabaseResponse, error)
    UpdateDatabase(ctx context.Context, req *UpdateDatabaseRequest) (*UpdateDatabaseResponse, error)
    DeleteDatabase(ctx context.Context, req *DeleteDatabaseRequest) error
    MGetDatabase(ctx context.Context, req *MGetDatabaseRequest) (*MGetDatabaseResponse, error)
    ListDatabase(ctx context.Context, req *ListDatabaseRequest) (*ListDatabaseResponse, error)
    GetDraftDatabaseByOnlineID(ctx context.Context, req *GetDraftDatabaseByOnlineIDRequest) (*GetDraftDatabaseByOnlineIDResponse, error)
    DeleteDatabaseByAppID(ctx context.Context, req *DeleteDatabaseByAppIDRequest) (*DeleteDatabaseByAppIDResponse, error)
    GetAllDatabaseByAppID(ctx context.Context, req *GetAllDatabaseByAppIDRequest) (*GetAllDatabaseByAppIDResponse, error)

    GetDatabaseTemplate(ctx context.Context, req *GetDatabaseTemplateRequest) (*GetDatabaseTemplateResponse, error)
    GetDatabaseTableSchema(ctx context.Context, req *GetDatabaseTableSchemaRequest) (*GetDatabaseTableSchemaResponse, error)
    ValidateDatabaseTableSchema(ctx context.Context, req *ValidateDatabaseTableSchemaRequest) (*ValidateDatabaseTableSchemaResponse, error)
    SubmitDatabaseInsertTask(ctx context.Context, req *SubmitDatabaseInsertTaskRequest) error
    GetDatabaseFileProgressData(ctx context.Context, req *GetDatabaseFileProgressDataRequest) (*GetDatabaseFileProgressDataResponse, error)

    AddDatabaseRecord(ctx context.Context, req *AddDatabaseRecordRequest) error
    UpdateDatabaseRecord(ctx context.Context, req *UpdateDatabaseRecordRequest) error
    DeleteDatabaseRecord(ctx context.Context, req *DeleteDatabaseRecordRequest) error
    ListDatabaseRecord(ctx context.Context, req *ListDatabaseRecordRequest) (*ListDatabaseRecordResponse, error)

    ExecuteSQL(ctx context.Context, req *ExecuteSQLRequest) (*ExecuteSQLResponse, error)

    BindDatabase(ctx context.Context, req *BindDatabaseToAgentRequest) error
    UnBindDatabase(ctx context.Context, req *UnBindDatabaseToAgentRequest) error
    MGetDatabaseByAgentID(ctx context.Context, req *MGetDatabaseByAgentIDRequest) (*MGetDatabaseByAgentIDResponse, error)
    MGetRelationsByAgentID(ctx context.Context, req *MGetRelationsByAgentIDRequest) (*MGetRelationsByAgentIDResponse, error)

    PublishDatabase(ctx context.Context, req *PublishDatabaseRequest) (*PublishDatabaseResponse, error)
}

type CreateDatabaseRequest struct {
    Database *entity.Database
}

type CreateDatabaseResponse struct {
    Database *entity.Database
}

type UpdateDatabaseRequest struct {
    Database *entity.Database
}

type UpdateDatabaseResponse struct {
    Database *entity.Database
}

5. 数据访问层

数据访问层负责数据库相关数据的持久化操作,采用Repository模式和DAO模式相结合的设计,确保数据访问的一致性和可维护性。

5.1 数据库Repository接口定义

文件位置 : backend/domain/memory/database/repository/repository.go

数据库数据访问层采用Repository模式,提供统一的数据访问接口。由于系统采用了草稿-线上分离的设计,提供了两个主要的Repository接口:DraftDAO和OnlineDAO,分别负责草稿态和线上态的数据库操作:

go 复制代码
// DraftDAO 草稿态数据库操作接口
type DraftDAO interface {
    Get(ctx context.Context, id int64) (*entity.Database, error)
    List(ctx context.Context, filter *entity.DatabaseFilter, page *entity.Pagination, orderBy []*database.OrderBy) ([]*entity.Database, int64, error)
    MGet(ctx context.Context, ids []int64) ([]*entity.Database, error)

    CreateWithTX(ctx context.Context, tx *query.QueryTx, database *entity.Database, draftID, onlineID int64, physicalTableName string) (*entity.Database, error)
    UpdateWithTX(ctx context.Context, tx *query.QueryTx, database *entity.Database) (*entity.Database, error)
    DeleteWithTX(ctx context.Context, tx *query.QueryTx, id int64) error
    BatchDeleteWithTX(ctx context.Context, tx *query.QueryTx, ids []int64) error
}

// OnlineDAO 线上态数据库操作接口
type OnlineDAO interface {
    Get(ctx context.Context, id int64) (*entity.Database, error)
    MGet(ctx context.Context, ids []int64) ([]*entity.Database, error)
    List(ctx context.Context, filter *entity.DatabaseFilter, page *entity.Pagination, orderBy []*database.OrderBy) ([]*entity.Database, int64, error)

    UpdateWithTX(ctx context.Context, tx *query.QueryTx, database *entity.Database) (*entity.Database, error)
    CreateWithTX(ctx context.Context, tx *query.QueryTx, database *entity.Database, draftID, onlineID int64, physicalTableName string) (*entity.Database, error)
    DeleteWithTX(ctx context.Context, tx *query.QueryTx, id int64) error
    BatchDeleteWithTX(ctx context.Context, tx *query.QueryTx, ids []int64) error
}

// 工厂方法
func NewDraftDatabaseDAO(db *gorm.DB, idGen idgen.IDGenerator) DraftDAO {
    return dal.NewDraftDatabaseDAO(db, idGen)
}

func NewOnlineDatabaseDAO(db *gorm.DB, idGen idgen.IDGenerator) OnlineDAO {
    return dal.NewOnlineDatabaseDAO(db, idGen)
}
创建方法特点
  • 事务支持: 所有写操作都支持事务,确保数据一致性
  • 类型安全: 使用强类型参数,避免运行时错误
  • 错误处理: 详细的错误信息,便于问题定位
  • 批量操作: 支持批量创建,提高性能

5.2 数据访问对象(DAO)

文件位置 : backend/domain/memory/database/internal/dal/

数据库的DAO实现采用了单例模式和工厂方法模式,分别为草稿态和线上态的数据库提供了独立的DAO实现:DraftImpl和OlineImpl。

go 复制代码
// DraftImpl 草稿态数据库DAO实现
type DraftImpl struct {
    IDGen idgen.IDGenerator
    query *query.Query
}

func NewDraftDatabaseDAO(db *gorm.DB, idGen idgen.IDGenerator) *DraftImpl {
    draftOnce.Do(func() {
        singletonDraft = &DraftImpl{
            IDGen: idGen,
            query: query.Use(db),
        }
    })
    
    return singletonDraft
}

// OlineImpl 线上态数据库DAO实现
type OlineImpl struct {
    IDGen idgen.IDGenerator
    query *query.Query
}

func NewOnlineDatabaseDAO(db *gorm.DB, idGen idgen.IDGenerator) *OlineImpl {
    onlineOnce.Do(func() {
        singletonOnline = &OlineImpl{
            IDGen: idGen,
            query: query.Use(db),
        }
    })
    
    return singletonOnline
}

// CreateWithTX 创建数据库记录(事务支持)
func (d *DraftImpl) CreateWithTX(ctx context.Context, tx *query.QueryTx, database *entity.Database, 
    draftID, onlineID int64, physicalTableName string) (*entity.Database, error) {
    now := time.Now().UnixMilli()
    
    draftInfo := &model.DraftDatabaseInfo{
        ID:              draftID,
        AppID:           database.AppID,
        SpaceID:         database.SpaceID,
        RelatedOnlineID: onlineID,
        IsVisible:       1, // visible by default
        PromptDisabled: func() int32 {
            if database.PromptDisabled {
                return 1
            } else {
                return 0
            }
        }(),
        TableName_:        database.TableName,
        TableDesc:         database.TableDesc,
        TableField:        database.FieldList,
        CreatorID:         database.CreatorID,
        IconURI:           database.IconURI,
        PhysicalTableName: physicalTableName,
        RwMode:            int64(database.RwMode),
        CreatedAt:         now,
        UpdatedAt:         now,
    }
    
    table := tx.DraftDatabaseInfo
    err := table.WithContext(ctx).Create(draftInfo)
    if err != nil {
        return nil, err
    }
    
    database.CreatedAtMs = now
    database.UpdatedAtMs = now
    
    return database, nil
}

// Get 获取单个数据库记录
func (d *DraftImpl) Get(ctx context.Context, id int64) (*entity.Database, error) {
    res := d.query.DraftDatabaseInfo
    
    info, err := res.WithContext(ctx).Where(res.ID.Eq(id)).First()
    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            return nil, errorx.New(errno.ErrMemoryDatabaseNotFoundCode)
        }
        return nil, fmt.Errorf("query draft database failed: %v", err)
    }
    
    // 构建返回的数据库对象
    db := &entity.Database{
        ID:        info.ID,
        SpaceID:   info.SpaceID,
        CreatorID: info.CreatorID,
        IconURI:   info.IconURI,
        
        AppID:           info.AppID,
        IsVisible:       info.IsVisible == 1,
        PromptDisabled:  info.PromptDisabled == 1,
        TableName:       info.TableName_,
        TableDesc:       info.TableDesc,
        FieldList:       info.TableField,
        Status:          table.BotTableStatus_Online,
        ActualTableName: info.PhysicalTableName,
        RwMode:          table.BotTableRWMode(info.RwMode),
        OnlineID:        &info.RelatedOnlineID,
        DraftID:         &info.ID,
    }
    
    return db, nil
}

// List 列表查询数据库记录
func (o *OlineImpl) List(ctx context.Context, filter *entity.DatabaseFilter, 
    page *entity.Pagination, orderBy []*database.OrderBy) ([]*entity.Database, int64, error) {
    res := o.query.OnlineDatabaseInfo
    
    // 构建基本查询
    q := res.WithContext(ctx)
    
    // 添加过滤条件
    if filter != nil {
        if filter.CreatorID != nil {
            q = q.Where(res.CreatorID.Eq(*filter.CreatorID))
        }
        
        if filter.SpaceID != nil {
            q = q.Where(res.SpaceID.Eq(*filter.SpaceID))
        }
        
        if filter.AppID != nil {
            q = q.Where(res.AppID.Eq(*filter.AppID))
        }
        
        if filter.TableName != nil {
            q = q.Where(res.TableName_.Like("%" + *filter.TableName + "%"))
        }
        
        q = q.Where(res.IsVisible.Eq(1))
    }
    
    // 计数
    count, err := q.Count()
    if err != nil {
        return nil, 0, fmt.Errorf("count online database failed: %v", err)
    }
    
    // 分页处理
    limit := int64(50) // 默认
    if page != nil && page.Limit > 0 {
        limit = int64(page.Limit)
    }
    
    offset := 0
    if page != nil && page.Offset > 0 {
        offset = page.Offset
    }
    
    // 排序处理
    if len(orderBy) > 0 {
        for _, order := range orderBy {
            switch order.Field {
            case "created_at":
                if order.Direction == table.SortDirection_Desc {
                    q = q.Order(res.CreatedAt.Desc())
                } else {
                    q = q.Order(res.CreatedAt)
                }
            case "updated_at":
                if order.Direction == table.SortDirection_Desc {
                    q = q.Order(res.UpdatedAt.Desc())
                } else {
                    q = q.Order(res.UpdatedAt)
                }
            default:
                q = q.Order(res.CreatedAt.Desc())
            }
        }
    } else {
        q = q.Order(res.CreatedAt.Desc())
    }
    
    // 查询数据
    records, err := q.Limit(int(limit)).Offset(offset).Find()
    if err != nil {
        return nil, 0, fmt.Errorf("list online database failed: %v", err)
    }
    
    // 转换为实体对象
    databases := make([]*entity.Database, 0, len(records))
    for _, info := range records {
        d := &entity.Database{
            ID:        info.ID,
            SpaceID:   info.SpaceID,
            CreatorID: info.CreatorID,
            IconURI:   info.IconURI,
            
            AppID:           info.AppID,
            DraftID:         &info.RelatedDraftID,
            OnlineID:        &info.ID,
            IsVisible:       info.IsVisible == 1,
            PromptDisabled:  info.PromptDisabled == 1,
            TableName:       info.TableName_,
            TableDesc:       info.TableDesc,
            FieldList:       info.TableField,
            Status:          table.BotTableStatus_Online,
            ActualTableName: info.PhysicalTableName,
            RwMode:          table.BotTableRWMode(info.RwMode),
            TableType:       ptr.Of(table.TableType_OnlineTable),
        }
        
        databases = append(databases, d)
    }
    
    return databases, count, nil
}
数据库操作特点
  • 单例模式: DAO实现采用单例模式,确保全局唯一实例
  • 事务支持 : 所有写操作都通过WithTX方法提供事务支持,确保数据一致性
  • 双重状态管理: 分别管理草稿态和线上态的数据,支持版本控制和发布流程
  • 分页与排序: List方法支持灵活的分页和排序功能
  • 错误处理: 提供详细的错误信息和适当的错误码映射
  • 过滤条件: 支持多维度的过滤条件,满足不同查询需求

5.3 完整数据访问流程

数据库创建涉及的数据表:

  1. draft_database_info: 草稿态数据库信息表
  2. online_database_info: 线上态数据库信息表
  3. physical tables: 实际存储数据的物理表

数据访问流程:

  1. 领域服务层接收请求并进行业务校验
  2. 生成唯一的草稿ID和线上ID
  3. 创建物理表(如果是新表)
  4. 开启数据库事务
  5. 通过DraftDAO创建草稿记录
  6. 通过OnlineDAO创建线上记录
  7. 提交事务
  8. 发布数据库创建事件

特点说明

  • 数据库采用了物理表与元数据表分离的设计
  • 草稿态和线上态数据同时创建,确保数据一致性
  • 事务贯穿整个创建流程,保证原子性操作

5.4 数据模型定义

文件位置 : backend/domain/memory/database/internal/dal/model/

数据库系统使用了两个主要的数据模型来分别表示草稿态和线上态的数据库信息:

go 复制代码
// DraftDatabaseInfo 草稿态数据库信息模型
type DraftDatabaseInfo struct {
    ID              int64                  `gorm:"column:id;primaryKey" json:"id"`
    AppID           int64                  `gorm:"column:app_id" json:"app_id"`
    SpaceID         int64                  `gorm:"column:space_id;not null" json:"space_id"`
    RelatedOnlineID int64                  `gorm:"column:related_online_id" json:"related_online_id"`
    IsVisible       int32                  `gorm:"column:is_visible;default:1" json:"is_visible"`
    PromptDisabled  int32                  `gorm:"column:prompt_disabled;default:0" json:"prompt_disabled"`
    TableName_      string                 `gorm:"column:table_name;not null;size:100" json:"table_name"`
    TableDesc       string                 `gorm:"column:table_desc;size:500" json:"table_desc"`
    TableField      []*database.FieldItem  `gorm:"column:table_field;type:json" json:"table_field"`
    CreatorID       int64                  `gorm:"column:creator_id;not null" json:"creator_id"`
    IconURI         string                 `gorm:"column:icon_uri;size:500" json:"icon_uri"`
    PhysicalTableName string               `gorm:"column:physical_table_name;size:255" json:"physical_table_name"`
    RwMode          int64                  `gorm:"column:rw_mode;default:0" json:"rw_mode"`
    CreatedAt       int64                  `gorm:"column:created_at;autoCreateTime:milli" json:"created_at"`
    UpdatedAt       int64                  `gorm:"column:updated_at;autoUpdateTime:milli" json:"updated_at"`
}

// OnlineDatabaseInfo 线上态数据库信息模型
type OnlineDatabaseInfo struct {
    ID              int64                  `gorm:"column:id;primaryKey" json:"id"`
    AppID           int64                  `gorm:"column:app_id" json:"app_id"`
    SpaceID         int64                  `gorm:"column:space_id;not null" json:"space_id"`
    RelatedDraftID  int64                  `gorm:"column:related_draft_id" json:"related_draft_id"`
    IsVisible       int32                  `gorm:"column:is_visible;default:1" json:"is_visible"`
    PromptDisabled  int32                  `gorm:"column:prompt_disabled;default:0" json:"prompt_disabled"`
    TableName_      string                 `gorm:"column:table_name;not null;size:100" json:"table_name"`
    TableDesc       string                 `gorm:"column:table_desc;size:500" json:"table_desc"`
    TableField      []*database.FieldItem  `gorm:"column:table_field;type:json" json:"table_field"`
    CreatorID       int64                  `gorm:"column:creator_id;not null" json:"creator_id"`
    IconURI         string                 `gorm:"column:icon_uri;size:500" json:"icon_uri"`
    PhysicalTableName string               `gorm:"column:physical_table_name;size:255" json:"physical_table_name"`
    RwMode          int64                  `gorm:"column:rw_mode;default:0" json:"rw_mode"`
    CreatedAt       int64                  `gorm:"column:created_at;autoCreateTime:milli" json:"created_at"`
    UpdatedAt       int64                  `gorm:"column:updated_at;autoUpdateTime:milli" json:"updated_at"`
}

### 数据模型的核心特点

1. **双重状态管理**:通过DraftDatabaseInfo和OnlineDatabaseInfo两个模型分别管理数据库的草稿态和线上态,实现了开发与生产环境的分离
   - 草稿态用于数据库的创建、编辑和预览
   - 线上态包含最终发布的数据库配置,提供稳定的数据访问服务

2. **字段关系**:两个模型之间通过RelatedDraftID和RelatedOnlineID字段相互关联,确保草稿与线上版本的对应关系

3. **物理表与元数据分离**:通过PhysicalTableName字段记录实际存储数据的物理表名,实现了元数据管理与数据存储的解耦

4. **字段定义**:使用TableField字段(JSON类型)存储表的字段定义信息,支持灵活的表结构配置

5. **访问控制**:通过RwMode字段控制数据库的读写模式,IsVisible和PromptDisabled控制数据库的可见性和提示功能

6. **时间戳管理**:自动维护CreatedAt和UpdatedAt时间戳,记录数据库的创建和更新时间

5.5 查询生成器

文件位置 : backend/domain/memory/database/internal/dal/query/

数据库系统使用GORM生成的查询接口,为草稿态和线上态数据库提供类型安全的查询方法:

go 复制代码
// 线上态数据库查询接口
type IOnlineDatabaseInfoDo interface {
    gen.SubQuery
    Debug() IOnlineDatabaseInfoDo
    WithContext(ctx context.Context) IOnlineDatabaseInfoDo
    WithResult(fc func(tx gen.Dao)) gen.ResultInfo
    ReplaceDB(db *gorm.DB)
    ReadDB() IOnlineDatabaseInfoDo
    WriteDB() IOnlineDatabaseInfoDo
    As(alias string) gen.Dao
    Session(config *gorm.Session) IOnlineDatabaseInfoDo
    Columns(cols ...field.Expr) gen.Columns
    Clauses(conds ...clause.Expression) IOnlineDatabaseInfoDo
    Not(conds ...gen.Condition) IOnlineDatabaseInfoDo
    Or(conds ...gen.Condition) IOnlineDatabaseInfoDo
    Select(conds ...field.Expr) IOnlineDatabaseInfoDo
    Where(conds ...gen.Condition) IOnlineDatabaseInfoDo
    Order(conds ...field.Expr) IOnlineDatabaseInfoDo
    Distinct(cols ...field.Expr) IOnlineDatabaseInfoDo
    Omit(cols ...field.Expr) IOnlineDatabaseInfoDo
    Join(table schema.Tabler, on ...field.Expr) IOnlineDatabaseInfoDo
    LeftJoin(table schema.Tabler, on ...field.Expr) IOnlineDatabaseInfoDo
    RightJoin(table schema.Tabler, on ...field.Expr) IOnlineDatabaseInfoDo
    Group(cols ...field.Expr) IOnlineDatabaseInfoDo
    Having(conds ...gen.Condition) IOnlineDatabaseInfoDo
    Limit(limit int) IOnlineDatabaseInfoDo
    Offset(offset int) IOnlineDatabaseInfoDo
    Count() (count int64, err error)
    Scopes(funcs ...func(gen.Dao) gen.Dao) IOnlineDatabaseInfoDo
    Unscoped() IOnlineDatabaseInfoDo
    Create(values ...*model.OnlineDatabaseInfo) error
    CreateInBatches(values []*model.OnlineDatabaseInfo, batchSize int) error
    Save(values ...*model.OnlineDatabaseInfo) error
    First() (*model.OnlineDatabaseInfo, error)
    Take() (*model.OnlineDatabaseInfo, error)
    Last() (*model.OnlineDatabaseInfo, error)
    Find() ([]*model.OnlineDatabaseInfo, error)
    // 更多查询方法...
}

// 草稿态数据库查询接口类似,命名为IDraftDatabaseInfoDo
相关推荐
枫叶丹42 小时前
金仓数据库替代MongoDB:电子证照系统国产化改造实战
数据库·mongodb
麦兜*2 小时前
Redis 7.0 新特性深度解读:迈向生产级的新纪元
java·数据库·spring boot·redis·spring·spring cloud·缓存
吾鳴3 小时前
扣子(Coze)实战:国庆中秋海报一键做,让你的效率翻10倍!
coze
可涵不会debug3 小时前
金仓数据库:破解电子证照国产化难题,开启政务效能新篇
数据库·政务
元闰子3 小时前
对 Agent-First 数据库的畅想
数据库·后端·aigc
java水泥工3 小时前
学科竞赛管理系统|基于SpringBoot和Vue的学科竞赛管理系统(源码+数据库+文档)
数据库·vue.js·spring boot
kobe_OKOK_3 小时前
django 数据库迁移
数据库·oracle·django
苏琢玉4 小时前
作为 PHP 开发者,我第一次用 Go 写了个桌面应用
node.js·go·php
寻星探路4 小时前
数据库造神计划第二十一天---JDBC编程
数据库·oracle