【问题标题】:Hazelcast replace(id, old, new) not calling my MapStoreHazelcast replace(id, old, new) 不调用我的 MapStore
【发布时间】:2018-03-27 03:58:44
【问题描述】:

我正在尝试在 Hazelcast 中实现乐观并发检查,如 here 所述。我已经将我的 MapConfigs 设置为使用 InMemoryFormat.OBJECT 并且我已经向我的 BaseEntity 添加了一个版本字段,其中 equals() 和 hashCode() 定义如下:

@Override
public boolean equals(Object o) {
  if (this == o)
    return true;
  if (o == null || getClass() != o.getClass())
    return false;

  BaseEntity that = (BaseEntity) o;

  return getId().equals(that.getId()) && getVersion() == that.getVersion();
}

@Override
public int hashCode() {
  return (int) (getId().hashCode() + version);
}

在我的 BaseService 中,我已将 map.replace(id, entity) 替换为 3 arg 版本,如下所示:

instance.incrementVersion();
if (getTransactionalMap().replace(instance.getId(), existing, instance)) {

  // do some stuff here
} else {
  throw new OptimisticConcurrencyServiceException(
        "Could not replace existing " + existing.getEntityId() + " with version " + existing.getVersion());
}

我遇到的问题是我的 MapStore 没有在更新时被调用。在一个事务中,我创建一个对象并通过我的 BaseService.create() 方法将其存储到地图中(这将调用我的 MapStore)然后我用它做一些其他事情并调用 service.update() 最终调用我的 doUpdate( ) 方法。此更新永远不会到达我的 MapStore,因此该值永远不会保留。当我使用替换方法的 2 arg 版本(replace(id, entity))时,这些更改确实到达了 MapStore,因此被保留了下来。有什么区别,我该如何让它发挥作用?

编辑:添加 update() 方法:

public void update(NestupSecurityContext context, String id, @Validated T entity) throws ServiceException {
  T existing = getOne(context, id);
  if (existing != null) {
    if (existing.equals(entity)) {
      T copy;
      try {
        copy = (T) existing.clone();
      } catch (CloneNotSupportedException e) {
        //shouldn't be possible
        throw new ServiceException(e);
      }
      copy.copyFrom(entity);
      doUpdate(context, existing, copy);
    } else {
      throw new OptimisticConcurrencyServiceException(
            entity.getEntityId() + " is out of date! Current version is " + existing.getVersion() + ", trying to save version " + entity.getVersion());
    }
  }
}

注释:

  1. equals() 检查版本,如上所述
  2. copyFrom() 是因为这些实体大多来自 REST 端点,并非所有值都可以通过 REST 端点设置。 copyFrom() 只复制可编辑的值,包括版本字段,当客户端调用以在更新之前获取实体时必须携带该字段。
  3. clone() 为我们提供了此事务读取的基本值的干净副本

【问题讨论】:

  • 你能在替换电话后检查你是否在拨打transactionContext.commitTransaction();吗?我刚刚尝试过,似乎它正在工作。您能否分享您正在运行这些操作、客户端或成员的完整 service.update() 方法、Hazelcast 版本和实例类型?
  • 添加了 update() 方法。我的 BaseService 和子类中的所有方法都应用了 @Transactional 注释,因此事务会在线程命中的第一个服务方法处自动打开和关闭。这始终适用于旧的 replace(id, entity) 版本的更新。我们在 Hazelcast 3.9.2 上运行,Hazelcast 嵌入在 Spring Boot 应用程序中运行。

标签: spring-boot hazelcast hazelcast-imap


【解决方案1】:

这是我的 copyFrom() 没有调用父类来复制版本的问题。我还需要让我的 update() 方法返回更新后的实例(与原始实例不同),因此如果代码需要继续使用该对象,它可以使用更新后的对象更新其引用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多