0

我有以下型号

type UsersModel struct {
    db           *pgx.Conn
}

func (u *UsersModel) SignupUser(ctx context.Context, payload SignupRequest) (SignupQueryResult, error) {
    err := u.db.Exec("...")
    return SignupQueryResult{}, err
}
type SessionsModel struct {
    db           *pgx.Conn
}
 
func (s *SessionsModel) CreateSession(ctx context.Context, payload CreateSessionRequest) error {
    _, err := s.db.Exec("...")
    return err
}

我的服务调用 UsersModel.SignupUser 如下

type SignupService struct {
    userModel signupServiceUserModel
}

func (ss *SignupService) Signup(ctx context.Context, request SignupRequest) (SignupQueryResult, error) {
    return ss.userModel.SignupUser(ctx, request)
}

现在,我需要绑定一个事务SignupUserCreateSession不是孤立的操作,不确定构建它的最佳方法是什么,以及如何在保持从服务中抽象出数据库特定内容的同时传递事务。或者我应该只调用会话表插入查询(我*SessionsModel.CreateSession 直接放入*UsersModel.SignupUser

作为参考,事务pgx通过调用*pgx.Conn.Begin() which 返回一个具体的发生pgx.Tx,您可以在其上执行与 *px.Conn 相同的功能,然后是*pgx.Tx.Commit()or*pgx.Tx.Rollback()

我的问题是:

  • 从哪里开始交易——模型还是服务?
  • 如果在服务中,我如何在从服务中抽象出底层数据库的同时做到这一点?
  • 如何在模型之间传递事务?
4

1 回答 1

0

对此没有正确或错误的答案,因为有多种方法可以做到这一点。但是,我分享了我会如何做以及为什么。

确保服务层没有任何具体的数据库实现,因此如果您切换到全新的数据库,则无需更改其他部分。

关于解决方案,我将创建一个全新的方法,称为SignupUserAndCreateSession包含您需要的所有逻辑。我不会担心,因为您将两种原始方法合二为一,根据我在这种情况下的理解,它们在设计上都是紧密耦合的,因此这不是反模式。

我会避免在方法之间移动,*pgx.Tx因为无论如何您将依赖另一个确保提交或回滚的级别,这可能会导致未来实现中的错误。

于 2021-11-04T07:54:18.923 回答