Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将SQL事务包装到现有存储库中,该存储库不';你不使用sql.Tx吗?_Sql_Go_Transactions_Domain Driven Design - Fatal编程技术网

如何将SQL事务包装到现有存储库中,该存储库不';你不使用sql.Tx吗?

如何将SQL事务包装到现有存储库中,该存储库不';你不使用sql.Tx吗?,sql,go,transactions,domain-driven-design,Sql,Go,Transactions,Domain Driven Design,我有一个一次性创建大量数据的服务。假设我创建了user->user pic->user contact->user address 我为每个域创建的每个表。比如说,在用户域中我有一个存储库来创建如下用户: stmt,err:=db.Prepare(查询) 检查错误(err) err=stmt.QueryRowContext(ctx,…data).Scan(…model) 检查错误(err) 回归模型 在我的例子中,每个存储库都使用一个Create语句,如上图所示,我不使用db.BeginTx(

我有一个一次性创建大量数据的服务。假设我创建了
user->user pic->user contact->user address

我为每个域创建的每个表。比如说,在
用户域中
我有一个存储库来创建如下用户:

stmt,err:=db.Prepare(查询)
检查错误(err)
err=stmt.QueryRowContext(ctx,…data).Scan(…model)
检查错误(err)
回归模型
在我的例子中,每个存储库都使用一个
Create语句
,如上图所示,我不使用
db.BeginTx()

这是我谈论的一项服务:

dataUser,errCreate:=user.repository.Create(ctx,modelUser)
dataPic,errCreatePic:=pic.repository.Create(ctx,modelUserPic)
dataContact,errCreateContact:=contact.repository.Create(ctx,modelUserContact)
dataAddress,errCreateAddress:=地址.存储库.创建(ctx,modelUserAddress)
但是如果一个调用失败,在中间,父节点将在这里被提交。是否可以在我创建的现有存储库中对该案例进行包装
事务


或者我应该在存储库中创建一个方法来处理例如
CreateWithTransaction()

很大程度上取决于整个体系结构的设置方式。有许多变化和考虑因素需要考虑(我不会详细讨论,因为有大量的文档)。但一般来说,最佳实践是域模型——在许多情况下甚至是服务——完全独立于任何实现选择。它不应该知道SQL事务

例如,如果
用户
是DDD术语中的聚合根,并且
图片
联系人
地址
是值对象,则
用户
负责一致性

在我自己的DDD代码中,我使用了一个体系结构和。我可能在应用程序层中有一个
UpdateUserDetails
命令,该命令被传递给存储库实现(例如,对于SQL数据库)并执行事务处理。域层只定义存储库接口

命令处理程序从存储库中检索聚合根对象,即
User
,并对其进行更新(同样,可以通过多种方式实现,例如在单个
User.UpdateDetails()
中或在处理程序本身的多个步骤中)。只有在没有任何验证或业务规则错误的情况下完成此操作后,处理程序才会持久化到存储库,这里我将调用包装到事务中

不过,我的代码非常具体,对您没有用处

取而代之的是,查看这个伟大的示例,以获得DDD for Go的完整介绍,包括事务处理。博客系列逐渐重构应用程序,引入更多与DDD相关的概念。它从一个“DDD lite”版本开始(最佳实践:开始时尽可能简单),然后添加CQR,甚至到事件源和微服务(由于“最终一致性”,事务处理方式将完全不同)


特别是本系列的文章,提供了一些关于如何处理事务的见解。

很大程度上取决于整个体系结构的设置方式。有许多变化和考虑因素需要考虑(我不会详细讨论,因为有大量的文档)。但一般来说,最佳实践是域模型——在许多情况下甚至是服务——完全独立于任何实现选择。它不应该知道SQL事务

例如,如果
用户
是DDD术语中的聚合根,并且
图片
联系人
地址
是值对象,则
用户
负责一致性

在我自己的DDD代码中,我使用了一个体系结构和。我可能在应用程序层中有一个
UpdateUserDetails
命令,该命令被传递给存储库实现(例如,对于SQL数据库)并执行事务处理。域层只定义存储库接口

命令处理程序从存储库中检索聚合根对象,即
User
,并对其进行更新(同样,可以通过多种方式实现,例如在单个
User.UpdateDetails()
中或在处理程序本身的多个步骤中)。只有在没有任何验证或业务规则错误的情况下完成此操作后,处理程序才会持久化到存储库,这里我将调用包装到事务中

不过,我的代码非常具体,对您没有用处

取而代之的是,查看这个伟大的示例,以获得DDD for Go的完整介绍,包括事务处理。博客系列逐渐重构应用程序,引入更多与DDD相关的概念。它从一个“DDD lite”版本开始(最佳实践:开始时尽可能简单),然后添加CQR,甚至到事件源和微服务(由于“最终一致性”,事务处理方式将完全不同)


特别是本系列的文章,提供了一些关于如何处理事务的见解。

而不是声明存储库,如

type UserRepo-struct{
db*sql.db
}
func(s UserRepo)创建(ctx context.context,u modelUser)错误{…}
喜欢签名,例如

类型执行器接口{
ExecContext(ctx context.context,查询字符串,args…接口{})(sql.Result,错误)
}
类型查询接口{
QueryContext(ctx context.context,查询字符串,args…接口{})(*sql.Rows,错误)
}
类型UserRepo struct{}
func(s UserRepo)创建(ctx context.context,db Execer,u modelUser)错误{…}
它添加了两个接口来抽象数据库的具体底层类型

因此,在调用者中,您可以编写类似于

db:=GetDB()
tx:=分贝。