背景
假设您有一个 (SOAP) Web 服务,BookService
用于管理图书馆中的书籍。在信息模型中假设Book
实体具有以下属性:
id
author
publisher
title
shelfId
为了操作数据,定义了四个 Web 服务操作:
AddBook
GetBook
UpdateBook
DeleteBook
为每个操作定义请求和响应消息。但是,更新消息 XML 模式的设计更为复杂。我们希望达到以下品质:
- R1:重置/删除属性的先前值的可能性。例如,说您不再将书保留在图书馆中,因此想重置/清空/删除该
shelfId
特定书的属性的属性值。 - R2:避免网络服务中的喋喋不休。请参阅反模式 Chatty Services。
- R3:为未来对并发控制和乐观锁定的需求做准备。我们可能希望最小化(或消除)根据旧信息进行更新的风险。
设计方案
我看到了三个市长备选方案,其中一个有几个子选项来设计更新消息:
- 发送整个业务文件。被遗漏的元素(
minOccurs="0"
在模式中)或元素明确设置为空,即<shelfId xsi:nil="true"/>
,将被解释为删除先前的值。 - 突出显示更改或仅发送差异。
- 发送整个业务文档,但使用特定于此目的的属性标记修改的元素。示例:
<author dirty="true">Hemingway<author/>
。然后,服务的提供者只更新那些标记为脏的元素并忽略其他元素。 - 在消息模式中,将除标识符之外的所有元素设置
id
为具有minOccurs="0"
。消费者只发送那些要修改的元素。遗漏的元素不能在语义上被解释为删除。为了删除一个值,NULL
必须使用显式 XML 值。示例:<shelfId xsi:nil="true"/>
。 - 发送整个业务文件,同时提交之前阅读文件的副本。然后,提供者可以比较两个文档并仅更新新文档和先前文档不同的那些属性。
- 发送整个业务文档,但使用特定于此目的的属性标记修改的元素。示例:
- 定义多个操作。不是只使用一个操作,而是
UpdateBook
根据您认为必须更新的元素定义多个操作,例如UpdateBookAuthor
,UpdateBookPublisher
等等。这些中的每一个都将只有强制元素,并且要删除元素,请使用 XML 的显式 NULL,例如<shelfId xsi:nil="true"/>
.
讨论
替代 3的优点是易于理解,但缺点是消费者需要调用多个操作,以防Book
要更新实体中的多个字段。这使得服务“健谈”(参见上面的 R3),从而导致性能下降。
Alt 2比Alt 1更复杂,但Alt 2有一些与乐观并发控制相关的优点:
- 对于每个字段的时间戳/版本的乐观锁定存储在数据库中的情况(例如
authorVersion
)=> Alt 2提供了一种让多个用户同时修改相同部分的不同部分的方法,例如author
和publisher
,Book
同时发生故障的风险较小。 - 对于在数据库中存储一个完整的单个时间戳/版本的乐观锁定的情况=> Alt 2相对于Alt 1
Book
没有真正的优势。即使更新只修改了一个字段,请求的版本号太旧也会导致错误。 - 对于不使用并发控制或乐观/悲观锁定的情况 =>替代2比替代1提供的覆盖旧数据的风险更小,但其他不一致的更改可能会带来问题。
还有另一种情况,其中Alt 2(和Alt 3 )比Alt 1具有优势。消费者可能不会存储有关Book
实体的所有数据。例如,如果机器人在更新书架信息时不需要跟踪(缓存)关于作者的信息,而只需要跟踪书架,则可以更有效地对从书架上挑选书籍的机器人进行编程。
替代2.3中的方法的一个优点是,消费者提交以前版本的完整副本而不是版本号或时间戳,即版本号或时间戳不需要数据库中的专用列。
总而言之,我会说Alt 2.2在大多数情况下看起来是最有吸引力的。这里的挑战在于反序列化 XML 的框架必须能够区分遗漏元素和显式设置为 NULL 的元素,例如<shelfId xsi:nil="true"/>
. 在此处查看有关此主题的帖子。
问题
您会选择哪种选择?您是否看到其他更好的选择?你怎么看讨论?