3.6 数据存储
我们已经了解了Go kit和我们自己的代码如何使用JSON负载接收HTTP请求、将其转换为Go结构体、调用服务实现以及将响应内容编码为JSON以返回给调用者。现在,让我们更深入地研究数据的持久存储。社交图谱服务负责维护用户之间的关注/被关注关系,存储这类数据有许多选择,包括关系型数据库、键值存储,当然还有图数据库,这可能是最自然的选择。在这个阶段,我选择使用关系型数据库,因为它熟悉、可靠,并且可以很好地支持以下必要的操作:
·关注
·取消关注
·获取关注用户信息
·获取关注信息
如果后面我们发现更喜欢使用不同的数据存储,或者想要使用某种缓存机制扩展关系型数据库,也会非常容易,因为这些数据存储隐藏在接口之后。它实际上使用了相同的接口,即SocialGraphManager。你可能还记得,社交图谱服务包在其工厂函数中接受SocialGraphManager类型的store参数:
由于社交图谱服务通过这个接口与它的数据存储进行交互,所以无须对服务本身进行任何代码更改就可以实现。我将利用这一点进行单元测试,在单元测试中,我会使用易于设置的内存数据存储,可以快速填充测试数据,并允许在本地运行测试。
让我们看一下内存中的社交图谱数据存储,该存储位于https://github.com/the-gigi/delinkcious/blob/master/pkg/social_graph_manager/in_memory_social_graph_store.go。
它的依赖关系非常少,只有SocialGraphManager接口和标准错误包。它定义了一个SocialUser结构体,该结构体包含一个用户名和它所关注的用户名,以及关注它们的用户名:
数据存储本身是一个名为InMemorySocialGraphStore的结构体,它包含用户名和相应的SocialUser结构体之间的映射:
这些都很常见,InMemorySocialGraphStore结构体实现了SocialGraphManager接口方法。例如,下面是Follow()方法:
在这一点上,没有必要过于关注它是如何工作的。这里想要传达的主要观点是,通过使用接口作为抽象,你可以获得很大的灵活性和清晰的关注点分离,这对于希望在测试期间开发系统或服务的特定部分很有帮助。如果你希望进行重大的更改,例如更改底层数据存储或交叉使用多个数据存储,那么构建一个接口可以帮到你。