作者回复: 关于 2,你说的返回自增 id 是一种很好的方法,很常用,但是它破坏了 CQRS 对于 Command 的 fire-and-forget 的要求。
当然,也有一些其它的办法,比如将 id 在客户端生成(这个生成可以是客户端自己生成,也可以是调用服务端的某一个生成 id 的接口生成),但这却又破坏了 REST 接口中 Create 方法不指定 id 的规约。
再有一个办法,是在客户端生成一个非主键、但被索引的特殊 id,例如 GUID,这样,生成了记录之后,客户端可以使用这个 GUID 去服务端获取这条数据,当然,缺点是需要额外的一列来放置 GUID,且要保证 GUID 的唯一性。
所以,上面介绍了三种方法,各有利弊,都比较常用。当然,也有一些其它的方法。
作者回复: 状态,其实就是数据。
Service 提供了一系列的过程方法,入参进,结果出,但是 Service 并未发生变化。
Model 则相反,可以创建、修改、删除,这就是状态的变化。
作者回复: 感谢回复。
关于你提到的“概念与逻辑”,做个说明。
我是这样认为的,学习全栈技术比较忌讳仅仅学习单个的具体技术,之前的文章和回复中我也多次提到过,毕竟技术种类花样繁多,我们还是需要适当做一些抽象,理解一些通用和共性的东西,既包括一些概念,也包括一些套路(模式)。当然,我们需要通过许多例子来理解它们,这是没错的。
作者回复: 好问题。我的理解是,返回值就一定程度上意味着解耦可能不够彻底,因为 Command 的理想状况是 fire and forget,所以它才是要求无返回的,存在返回值意味着有一部分逻辑可以拿出去变成 Query。客户端只知道执行成功了,或者执行失败了(有异常抛出)。但是我们在应用到实际系统中的时候,不一定能够做到那么纯粹。
作者回复: 👍
作者回复: 关于 1) 这个理解不对。你可以再阅读一下文章,里面有说贫血模型和充血模型是根据什么来区别的。
作者回复: 无论是贫血模式还是充血模式,Model 层包含的内容都是一致的:逻辑+数据,区别是前者把它们分开、分别容纳在无逻辑的 Model 实体对象和无状态的 Service 中,后者则是统一存放在有状态且有逻辑的 Model 实体对象中。你的疑问是贫血模型下脱离 Service 之后的 Model 实体对象吧,它们只剩下数据,而很少包含,或者不包含逻辑,特别是业务逻辑。
作者回复: 👍
作者回复: 关于第 2 问,消息编号的想法很好,但是,消息编号是消息编号,而写入数据库对象的 id 是对象的 id,二者并没有必然联系啊。
作者回复: 第二个问题不对,因为通过 id 排序的方式,在数据量较大的时候不可行;而且,即便能排序,你也不能保证一定能找到那个你刚插入的数据(考虑两条数据并发写入的情况)。这个问题你可以看一下其它人的答复和回复