【问题标题】:Efficient transaction wrapper function with mongodb go driver带有 mongodb go 驱动程序的高效事务包装函数
【发布时间】:2022-08-16 14:20:50
【问题描述】:

我目前正在将事务逻辑集成到我的 go+mongodb api 中。

我已经创建了这个示例端点。它允许您检索用户文档并使用 json 编码将其发送回客户端。

func GetUser(w http.ResponseWriter, r *http.Request) {
    id := mux.Vars(r)[\"user-id\"]
    objectId, _ := primitive.ObjectIDFromHex(id)

    user, err := UserById(objectId)
    if err != nil {
        // ...
    }

    // do some stuff with the user, whatever

    // eventually send it back
    json.NewEncoder(w).Encode(user)
}

func UserById(id primitive.ObjectID) (models.StoredUser, error) {
    session, err := mongoClient.StartSession()
    if err != nil {
        return models.StoredUser{}, fmt.Errorf(\"failed starting session for transaction | %s\", err.Error())
    }
    defer session.EndSession(context.TODO())

    callback := func(ctx mongo.SessionContext) (any, error) {
        res := usersCollection.FindOne(
            ctx,
            bson.M{
                \"_id\": id,
            },
        )

        if res.Err() != nil {
            return models.StoredUser{}, fmt.Errorf(\"failed querying db | %s\", res.Err())
        }

        return res, nil
    }

    result, err := session.WithTransaction(context.TODO(), callback)
    if err != nil {
        return models.StoredUser{}, fmt.Errorf(\"failed executing transaction | %s\", err.Error())
    }

    asserted := result.(*mongo.SingleResult)
    var ret models.StoredUser
    if err := asserted.Decode(&ret); err != nil {
        return models.StoredUser{}, fmt.Errorf(\"failed parsing user data in struct | %s\", err.Error())
    }

    return ret, nil
}

以下是主要步骤:

  1. 解析请求内容获取用户id
  2. 创建会话以执行事务
  3. 使用 id 参数声明回调函数
  4. 从事务调用回调函数
  5. 取回*mongo.SingleResult 作为interface{} 并将其解析回其原始类型
  6. 解码*mongo.SingleResult中包含的bson文档,放入return struct

    此函数有效,但非常冗长。代码非常重复。

    我想知道是否有一种方法可以不为我想要制作的每个功能重复相同的代码。我之前的包装函数尝试没有产生任何结果,因为我实际上需要它们现在在每次调用时所在的变量。

    尽管如此,第 2 步和第 5 步似乎显得非常多余和低效。

    有人知道吗?

    标签: mongodb go transactions


    【解决方案1】:

    好的,我发现了以下内容:

    func Transaction(callback func(ctx mongo.SessionContext) (any, error)) (any, error) {
        session, err := mongoClient.StartSession()
        if err != nil {
            return nil, fmt.Errorf("failed creating session | %s", err.Error())
        }
    
        defer session.EndSession(context.TODO())
    
        res, err := session.WithTransaction(ctx, callback)
        if err != nil {
            return nil, fmt.Errorf("failed executing transaction | %s", err.Error())
        }
    
        return res, nil
    }
    

    假设我想获取用户对象:

    
    func GetUsers() ([]models.User, error) {
        callback := func(ctx mongo.SessionContext) (any, error) {
            res, err := usersCollection.Find(ctx, bson.M{})
            if err != nil {
                return nil, fmt.Errorf("failed querying users collection | %s", err.Error())
            }
    
            var ret []models.User
            if err := res.All(context.TODO(), &ret); err != nil {
                return nil, fmt.Errorf("failed parsing results in struct | %s", err.Error())
            }
    
            return ret, nil
        }
    
        result, err := Transaction(callback)
        if err != nil {
            return []models.User{}, fmt.Errorf("failed executing transaction | %s", err.Error())
        }
    
        classes, _ := result.([]models.StoredClass)
        return classes, nil
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-26
      • 2022-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-13
      相关资源
      最近更新 更多