数据库:具有NoSQL /文档数据库(DDD)的存储库

时间:2018-07-29 17:49:13

标签: database orm nosql domain-driven-design repository-pattern

正在寻找将其存储库从关系数据库迁移到NoSQL的任何人的建议吗?

我们当前正在使用Postgres数据库和ORM(SQLAlchemy)构建应用程序。但是,有可能以后我们可能需要将App迁移到当前仅支持几种NoSQL解决方案的环境。

考虑到这一点,我们正在遵循持久化方法来处理Vaughn Vernon的《实现域驱动设计》中涵盖的存储库。这将产生以下API:

save(aggregate)
save_all(aggregates)
remove(aggregate)
get_by_...

无需详细说明,特定于ORM的代码已隐藏在存储库本身中。会话仅在检索或更新数据然后立即提交和关闭(在repos方法中)的短时间内使用。这意味着要在保存时进行大量合并,而不是最有效地使用Session。

def save(aggregate):
try:
session.merge(aggregate)
commit
except:
rollback

def get():
try:
aggregate = session.query_by(id)
session.expunge
commit
except:
rollback
return aggregate

等等等

优点:

  • 我们将自己限制为每个用例仅更新一个汇总,因此在应用程序服务中缺乏充分利用UOW事务控制的情况极少(性能之外)。在写入汇总时,将在回购中启用事务控制,以确保完整的汇总得以保留。
  • 在存储库外部没有任何特定于ORM的代码泄漏,无论如何,在切换到NoSQL db的出现之前,需要对其进行重新编码。

因此,如果我们必须切换到NoSQL DB,我们应该要做的工作最少。

但是,我阅读的几乎所有内容都鼓励事务性行为存在于应用程序服务层中。尽管我相信Business Transactional和DB Transactional之间存在区别。

同样,我们正在影响性能,因为我们要求会话工厂在每次调用存储库时进行一次会话。大多数服务包含大约3个对存储库的调用。

那么,对于从Relational迁移到NoSQL DB的任何人来说,这是一个问题吗?

  • 工作单元/会话的概念在NoSQL世界中意味着什么吗?

  • 我们是否应该同时完全接受ORM,并将UOW /会话从存储库之外移至应用程序服务中?

  • 如果这样做的话,如果最终需要迁移到NoSQL解决方案,那么重新设计应用程序服务的工作量是多少? (在任何情况下都需要重写存储库。)

  • 最后,有人在编写与实现无关的存储库方面有很多经验吗?

PS。理解我们可以完全删除ORM并同时使用纯SQL,但是我们被要求确保我们正在使用ORM。

2 个答案:

答案 0 :(得分:1)

编辑:在此答案中,我重点关注基于问题标题的文档数据库。当然,存在其他NoSQL存储,它们具有截然不同的特征(例如,使用事件源等的图数据库)。


这真的不是问题。

在文档数据库中,您的整个集合应该是一个文档。这样,您就可以完全相同地保证事务一致性。无论聚合中有多少实体发生更改,您仍在存储文档。您需要确保执行某种形式的开放式并发(通过etag或版本或类似方法),而不是工作单元模式,但是在此之后,您的交易要求就可以满足了。

我现在无法真正评论您是否完全采用UoW模式,还是依赖ORM实现等。这实际上很大程度上取决于您的当前状况和实现细节。我可以说的是,您很有可能不需要一次从标准格式(SQL)迁移到文档。从一个简单的例子开始,这样您就可以看到对您有用的,对您无效的。

我不知道与实现无关的存储库是否存在,但这对我来说意义不大。存储库的重点是封装持久性,因此您不能抽象化它:不会向他们分配任何其他职责。另外,您不能假定存储库需要将不同的模型组合到聚合模型中:这是特定于平台的,因此不是不可知的。

另一个最后的评论:在您的问题中,我看到您写了save_all(aggregates)的文档。我不确定您要指的是什么,但是至少每个聚合保存都应包装在自己的事务中,否则此操作违反了Aggregate的事务边界特性。

答案 1 :(得分:0)

  

工作单元/会话的概念在NoSQL中是否有意义?   世界?

是的,它仍然是一个有趣的概念。仅仅因为您正在使用NoSQL存储,并不意味着不再需要某种业务事务管理。许多NoSQL数据库都有驱动程序或第三方库来管理更改跟踪。例如,请参见RavenDB

当然,如果您每笔交易仅加载一个汇总,并且您的NoSQL存储单元与汇总完全匹配,那么大多数工作单元功能将不再那么重要,但是您仍将面临例外规则。此外,UoW中无论如何都与之相关的部分是提交,甚至可能中止。

  

同时我们应该完全接受ORM并移动   存储库外部的UOW /会话进入应用程序服务?

相反,我建议在完整的课程中具体体现“工作单元”的概念:

class UnitOfWork {
  void Commit() 
  {
    // Call your ORM persistence here
  }
}

应用程序服务只是工作单元的调用位置,而不是其实现的位置。

  

如果我们这样做,重新设计产品的工作量是多少?   应用服务,如果我们需要迁移到NoSQL解决方案中   结束。 (在任何情况下都需要重写存储库。)

这取决于许多其他参数,例如NoSQL API或第三方库对工作单元的支持,以及聚合和NoSQL存储之间的形状相似。它的范围从几乎没有工作到自己编写完整的UoW /变更跟踪实现。如果是后者,那么从存储库中将UoW逻辑提取到一个单独的类将不是最困难的工作。

  

最后,任何人都具有编写不可知的实现的丰富经验   存储库?

我在这里同意SKleanthous-与实现无关的存储库在IMO中没有多大意义。您已经有了存储库抽象(接口),它们当然是不可知的,但是当涉及到实现时,您必须处理特定的持久性存储。