我有一个自定义实体,该实体具有接近实时的更新(每分钟大约1000个更新)。由于同一实体记录可以在不同的批处理更新请求中得到更新,并且请求是从不同的异步源接收到的,因此CDS中较新的更新有可能被稍早的更新所覆盖。
由于网络延迟或其他原因,S1服务稍慢,服务S2继续进行,并在8.03 PM修改了对数据为Entity Record A的更新。
Service-1现在在同一实体记录上触发Update-1,并且在8.03PM发生的更新被在8.02PM发生的更新覆盖,从而导致数据丢失。
我已经在第10阶段(预验证)为我的自定义实体的Update SDK消息注册了一个插件。 该插件将输入参数中的datamodifiedon属性与插件上下文中的实体前图像中的一组进行比较。 如果先行实体映像已经具有更新的datamodifiedon属性,则抛出Invalid Plugin Execution异常。
// If ModifiedOn value in pre-image is later than the one received in input parameters, this is an obsolete request and must be rejected.
if (preImage.Contains("datamodifiedon")
&& preImage.GetAttributeValue<DateTime>("datamodifiedon") != DateTime.MinValue
&& entity.Contains("datamodifiedon")
&& entity.GetAttributeValue<DateTime>("datamodifiedon") != DateTime.MinValue
)
{
if (DateTime.Compare(preImage.GetAttributeValue<DateTime>("datamodifiedon"), entity.GetAttributeValue<DateTime>("datamodifiedon")) > 0)
{
string traceMessage = "PreOperationLiveWorkItemUpdatePlugin: Update request is obsolete. datamodifiedon field found in pre-entity image: "
+ preImage.GetAttributeValue<DateTime>("datamodifiedon")
+ "datamodifiedon field in Input parameters: "
+ entity.GetAttributeValue<DateTime>("datamodifiedon");
tracingService.Trace(traceMessage);
throw new InvalidPluginExecutionException(traceMessage);
}
}
由于更新非常频繁,因此有可能 1. Update-2(在8.03 PM修改数据)处于预验证阶段。成功验证后,正在进行数据库中的实际更新。 2.现在Update-1进入预验证阶段。由于Update-2尚未提交到数据库中,因此在此阶段接收到的实体图是否仍然是旧值,并允许验证通过?
由于其他两个阶段在同一个数据库事务中执行,是否会在操作前或操作后阶段而不是验证前阶段注册此插件?
还有其他方法可以解决此并发问题吗?由于更新是通过批量odata调用启动的,因此无法在请求标头中使用eTag前提条件。
答案 0 :(得分:0)
您要在预操作步骤中注册此插件。我认为您对实体图可能很脏感到担忧(我不确定是否在交易中检索到了实体图),所以与其使用实体图来检索记录的新副本并检查已检索记录的时间戳与目标上的时间戳的比较。由于您的所有操作都是针对同一表的同步事务,并且时间戳是该表上的字段,因此我认为这将确保您不会进行任何脏写。
但是:
如果您的Update1和Update2操作更新了不同的字段,那么现在您可能会遭受反向数据丢失。如果Update1设置了字段A,update2设置了字段B,则所做的更改
如果在更新到字段B之后对其进行处理,则将忽略字段A。
答案 1 :(得分:0)
您应该尝试使用Optimistic concurrency。如果可以在更新前检查行版本。
开放式并发功能使您的应用程序能够在应用程序检索记录与尝试更新或删除该记录之间的时间内检测到服务器上的实体记录是否已更改。