在单条 OData 更新请求里,ETag 的工作方式相当直观。客户端读取一条业务数据时拿到当前版本的 ETag,提交PATCH、PUT或DELETE时,再通过If-Match把这个 ETag 带回服务器。SAP Gateway 对客户端传入的 ETag 和服务器当前实体版本进行比较,只要两边不一致,就能够判断这条数据已经被其他事务修改过,正常情况下会拒绝这次写入。SAP Gateway 官方文档明确说明,当客户端提供的 ETag 与服务端计算出的 ETag 不一致时,会产生HTTP 412 Precondition Failed。
真正麻烦的地方出现在$batch。
一个$batch请求里可以包含 changeset,而一个 changeset 又可以同时塞进多条CREATE、UPDATE、DELETE,甚至 Action 操作。单看每一个请求,它们的 ETag 都可能完全正确,可一旦这些操作开始按照顺序修改同一批业务对象,前面的操作就可能改变后面操作即将访问的数据版本。
于是会出现一个很有意思的现象,客户端发送请求的时候 ETag 并没有过期,但 changeset 执行到一半,它却被 changeset 自己弄过期了。
这类问题并不是浏览器、SAPUI5 或 ODataModel 造成的,而是批处理事务边界和乐观并发控制结合以后自然产生的问题。
SAP Gateway 为此提供了一套专门的 changeset