因此,我正在开始微服务之路。我已经花了几个小时上网尝试使自己沉迷于这个主题。
我还不太了解的一个概念是不使用SQL连接的想法,因此对于作者和书本都有一个小的独立数据库。
所以我了解以下SQL:
BooksTable - id, name, authorid
AuthorsTable - id, name
select book.name, author.name from book
join author on book.authorId = author.id
在Node.js世界中
index.js
app.get('/api/books' bookDomain.get());
bookDomain.js
exports.get = () => {
const books = bookService.get();
const authors = authorService.get();
/*
This is where I'm lost: how do you achieve the simple SQL
above? I'm assuming in the domain is where this information is
"joined"? am I correct?
*/
};
服务
Database1
**bookService.js**
database context
Database2
**authorService.js**
database context
期望的数据(类似它,基本上我是说JSON应该是返回类型)
[{
book {
"name": "Book 1",
"author": "Author Name 1"
}
},
{
book {
"name": "Book 2",
"author": "Author Name 2"
}
}]
答案 0 :(得分:8)
我至少可以想到三种方法来解决此问题。
Books
和Authors
的表以及AuthorBooks
表都连接在一对外键上的关系数据库–您的书籍以BSON格式存储为文档类型,看起来与问题中的JSON几乎相同。像Mongo这样的文档数据库的一个不错的功能是,您可以在Book
的{{1}}文档内的JSON上建立索引,从而缩短查询时间。 Martin Fowler在NoSQL Distilled中对此进行了很好的讨论(第2.2节和第9章)。Author
答案 1 :(得分:4)
在这种情况下,需要两个单独的服务的基本想法令人怀疑,
因为1
位作者可能写过N
本书,而1
本书也可以有N
位作者。而且,必须使用自己的数据库的想法似乎令人怀疑-因为有node-isbn之类的库,可以将其包装到服务中,可以查询作者,标题和ISBN号。>
答案 2 :(得分:2)
对于我来说,我们可以选择以下选项:
在服务器上执行映射。图书服务从数据库获取图书列表,然后获取authorId,并使用它们在内部调用作者服务以获取作者姓名。
让客户端执行延迟加载。在这种情况下,图书服务返回图书列表(id,名称,authorId)。然后,客户端需要聚合authorId列表并调用作者服务以获取作者的姓名。最后,客户自己制作地图。
反规范化数据库。我们有2个选项
选项1:将authorName列添加到图书DB。
选项2:有一个新的NoSQL数据库来缓存书籍和作者的数据。有了此选项,它也适合大型应用程序,在这种应用程序中,获取数据的请求量很大(甚至需要搜索和其他查询要求)。
在上述2个选项中。我们需要确保对author表的所有更改都必须同步到相关的非规范化信息。
答案 3 :(得分:2)
我首选的方式如下:
首先,正如其他人已经提到的,是否需要AuthorService
还是在Book
上太近而可能成为BookService
的一部分是有争议的。 / p>
因此,在此示例中,我将其命名为PersonService
,因为您的未来ConferenceService
可以使用它。
通过采用微服务方法,您必须了解要实现的两个目标:
这意味着不允许 共享这两个服务(在物理上,但在逻辑上可能是相同的),因此BookService
无法修改PersonService
。这只能由PersonService
来完成。否则,内聚行为会受到威胁。
因此,我们有两个服务,每个服务都有一个单独的数据库。
我假定这两个服务都使用RESTful API,这很棒,因为我们想松耦合。 JSON可能看起来像这样:
[{
book {
"name": "Book 1",
"author": {
"name": "Author Name 1"
"href": "apis.yourdomain.com/personservice/persons/1"
"type": "application/json"
}
}
},
{
book {
"name": "Book 2",
"author": {
"name": "Author Name 2"
"href": "apis.yourdomain.com/personservice/persons/2"
"type": "application/json"
}
}
}]
如您所见,这些作者仅表示为Link
的引用PersonService
(中的实体)。这种耦合是松散的,因为在应用程序的整个生命周期中,Link
作为Person
的表示形式变化的可能性较小。
通过命名字段author
,您还将获得Book
和Person
之间关系的语义。
当然,前端应用程序通常不希望显示页面的请求太多,因此必须通过扩展Links
来考虑这一点。我更喜欢有一个Model
-objekt,它仅包含Links
和一个Representation
-对象,该对象的对应模型的链接通过调用Link
进行了扩展。如果您不想进行基于时间的缓存,这对我来说非常有用。
但是事情很容易变得复杂。假设有一个规则,例如“域对象只能由相应的服务发出”,以实现内聚行为。这意味着仅BookService
被允许传递Book
。现在想象一个请求,例如“ Martin Fowler的所有书籍”。应该查询哪个服务?按照上述规则,它应该是BookService
。但是BookService
怎么知道一个叫Martin Fowler的东西,他只知道Books
?
在这种情况下,有一个叫做非权威性缓存的东西(也可以持久保存在数据库中)。这仅表示允许BookService
将Person
存储在高速缓存或数据库中,但不允许与其他用户共享。
这样,仍然遵循上述规则,并且内聚行为仍在眼前。
非权威性缓存不需要反映完整的域对象Person
,而是反映满足用例所需的一切。