showliuzp 2025-10-01 21:23 采纳率: 84.5%
浏览 2
已结题

golang封装mongo查询完统一关闭资源


//根据礼物id列表查询指定的礼物
func GetGiftListByIds(gift_ids []int64,projection bson.M)(list []models.LuGiftList,err error){
    cur, err := mongo_coll(gift_table).Find(ctx, bson.M{"status":1,"_id":bson.M{"$in":gift_ids}},options.Find().SetProjection(projection))
    defer func(){
        cur.Close(ctx)
    }()

    if err != nil {
        return
    }

    err = IterateCursor(cur,&list)


    return
}


func UserBusinessStreamerList(req *iapi.UserBusinessStreamerListReq)(list []models.LuUserInfo,count int64,err error){
    filter := bson.M{"flag":types.USER_STREAMER,"p_staff":(*req).BusinessId}

    if (*req).StreamerId !=0{
        filter["_id"] = (*req).StreamerId
    }

    if len((*req).StreamerName) != 0{
        filter["nick_name"] = bson.M{"$regex":(*req).StreamerName}
    }

    count,err = mongo_coll_count(mongo_coll,user_table,filter)
    if err != nil{
        return
    }

    if count < 1{
        return
    }

    skip := int64(int64((*req).Page - 1) * int64((*req).PageSize))
    find_options := options.Find().SetSkip(skip).SetLimit(int64((*req).PageSize))

    sort_option := options.Find().SetSort(bson.D{{"_id", -1}})
    cur, err := mongo_coll(user_table).Find(ctx, filter,find_options,sort_option)

    defer func(){
        cur.Close(ctx)
    }()


    if err != nil {
        return
    }

    list,err = user_info_range_list_comm(ctx,cur)

    return
}


GetGiftListByIds、UserBusinessStreamerList都有执行如下函数
defer func(){
        cur.Close(ctx)
    }()

我想封装一个通用的函数,在函数执行完后自动执行
defer func(){
cur.Close(ctx)
}
  • 写回答

5条回答 默认 最新

  • 檀越@新空间 2025-10-01 21:24
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    为了实现统一关闭MongoDB查询资源的功能,我们可以将cur.Close(ctx)的逻辑封装到一个通用函数中,这样可以避免在多个函数中重复编写defer cur.Close(ctx)代码。这种方式不仅提高了代码的可维护性,也减少了出错的可能性。


    ✅ 一、目标

    • 封装一个通用函数,在执行完MongoDB查询后自动关闭游标(cur)。
    • 确保所有使用该函数的调用者都能正确关闭资源
    • 提供清晰的结构和示例代码。

    ✅ 二、解决方案

    1. 创建通用的MongoDB查询函数

    我们定义一个通用的函数 QueryWithCursor,它接收查询条件、投影、排序等参数,并返回游标和错误。同时,在函数内部使用 defer cur.Close(ctx) 来确保资源被释放。

    func QueryWithCursor(
        ctx context.Context,
        collectionName string,
        filter bson.M,
        opts ...*options.FindOptions,
    ) (*mongo.Cursor, error) {
        coll := mongo_client.Database("your_db_name").Collection(collectionName)
        cur, err := coll.Find(ctx, filter, opts...)
        if err != nil {
            return nil, err
        }
    
        // 自动关闭游标
        defer func() {
            cur.Close(ctx)
        }()
    
        return cur, nil
    }
    

    注意: 需要根据实际数据库配置初始化 mongo_client


    2. 使用封装后的通用函数修改原有函数

    修改 GetGiftListByIds

    func GetGiftListByIds(gift_ids []int64, projection bson.M) (list []models.LuGiftList, err error) {
        filter := bson.M{"status": 1, "_id": bson.M{"$in": gift_ids}}
        opts := options.Find().SetProjection(projection)
    
        cur, err := QueryWithCursor(ctx, gift_table, filter, opts)
        if err != nil {
            return nil, err
        }
    
        err = IterateCursor(cur, &list)
        return list, err
    }
    

    修改 UserBusinessStreamerList

    func UserBusinessStreamerList(req *iapi.UserBusinessStreamerListReq) (list []models.LuUserInfo, count int64, err error) {
        filter := bson.M{"flag": types.USER_STREAMER, "p_staff": (*req).BusinessId}
    
        if (*req).StreamerId != 0 {
            filter["_id"] = (*req).StreamerId
        }
    
        if len((*req).StreamerName) != 0 {
            filter["nick_name"] = bson.M{"$regex": (*req).StreamerName}
        }
    
        count, err = mongo_coll_count(mongo_coll, user_table, filter)
        if err != nil {
            return
        }
    
        if count < 1 {
            return
        }
    
        skip := int64(((*req).Page - 1) * (*req).PageSize)
        findOptions := options.Find().SetSkip(skip).SetLimit(int64((*req).PageSize))
        sortOptions := options.Find().SetSort(bson.D{{"_id", -1}})
    
        cur, err := QueryWithCursor(ctx, user_table, filter, findOptions, sortOptions)
        if err != nil {
            return
        }
    
        list, err = user_info_range_list_comm(ctx, cur)
        return
    }
    

    ✅ 三、关键点总结

    1. 通用函数封装

      • QueryWithCursor 是一个封装好的函数,用于执行MongoDB查询并自动关闭游标。
      • 它接受上下文、集合名、过滤条件以及查询选项。
    2. 资源管理

      • QueryWithCursor 中使用 defer cur.Close(ctx) 确保资源及时释放。
      • 这样即使发生错误或提前返回,也能保证资源不会泄漏。
    3. 代码复用

      • 所有需要查询MongoDB的函数都可以使用这个通用函数,避免重复代码。
      • 提高了代码的可读性和可维护性。

    ✅ 四、注意事项

    • 确保 mongo_client 已经正确初始化。
    • 如果使用了多个数据库或集合,建议进一步抽象为 DatabaseCollection 的参数。
    • 如果你使用的是 Go 模块,请确保导入正确的 MongoDB 包(如 go.mongodb.org/mongo-driver/mongo)。

    ✅ 五、完整示例代码(可直接使用)

    package main
    
    import (
        "context"
        "go.mongodb.org/mongo-driver/bson"
        "go.mongodb.org/mongo-driver/mongo"
        "go.mongodb.org/mongo-driver/mongo/options"
    )
    
    var mongo_client *mongo.Client
    var ctx context.Context
    
    func init() {
        // 初始化 MongoDB 客户端
        clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
        var err error
        mongo_client, err = mongo.Connect(ctx, clientOptions)
        if err != nil {
            panic(err)
        }
    }
    
    func QueryWithCursor(
        ctx context.Context,
        collectionName string,
        filter bson.M,
        opts ...*options.FindOptions,
    ) (*mongo.Cursor, error) {
        coll := mongo_client.Database("your_db_name").Collection(collectionName)
        cur, err := coll.Find(ctx, filter, opts...)
        if err != nil {
            return nil, err
        }
    
        defer func() {
            cur.Close(ctx)
        }()
    
        return cur, nil
    }
    

    如果你还有其他业务逻辑需要封装,也可以继续扩展这个通用函数,例如支持分页、聚合查询等。欢迎继续提问!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 10月10日
  • 已采纳回答 10月2日
  • 创建了问题 10月1日