5

我正在尝试在我的应用程序中使用 Hazelcast 实现分布式缓存。我正在使用 Hazelcast 的IMap. 我遇到的问题是每次从地图中获取值并更新值时,我都需要再做put(key, value)一次。如果我的值对象有 10 个属性并且我必须更新所有 10 个属性,那么我必须调用put(key, value)10 次。就像是 -

IMap<Integer, Employee> mapEmployees = hz.getMap("employees");
Employee emp1 = mapEmployees.get(100);
emp1.setAge(30);
mapEmployees.put(100, emp1);
emp1.setSex(“F”);
mapEmployees.put(100, emp1);
emp1.setSalary(5000);
mapEmployees.put(100, emp1);

如果我不这样做,则对同一 Employee 对象进行操作的其他一些节点将对其进行更新,最终结果是该员工对象不同步。有什么解决方案可以避免多次明确调用 put 吗?在 aConcurrentHashMap中,我不需要这样做,因为如果我更改对象,地图也会更新。

4

5 回答 5

8

从 3.3 版开始,您需要使用 EntryProcessor:

您在这里真正想做的是构建一个EntryProcessor<Integer, Employee>并使用它调用它 mapEmployees.executeOnKey( 100, new EmployeeUpdateEntryProcessor( new ObjectContainingUpdatedFields( 30, "F", 5000 ) );

这样,Hazelcast 处理锁定该 Employee 对象的键上的映射,并允许您以process()原子方式运行 EntryProcessor 方法中的任何代码,包括更新映射中的值。

因此,您将EntryProcessor使用一个自定义构造函数来实现,该构造函数接受一个包含您要更新的所有属性的对象,然后process()构造最终Employee将出现在地图中的对象并执行entry.setValue(). 不要忘记为可以序列化对象的新对象创建一个新StreamSerializer对象EmployeeUpdateEntryProcessorEmployee这样您就不会被 java.io 序列化所困。

来源:http: //docs.hazelcast.org/docs/3.5/manual/html/entryprocessor.html

于 2015-10-26T16:54:38.860 回答
2

可能交易是您需要的。或者你可能想看看分布式锁

请注意,在您的解决方案中,如果此代码由两个线程运行,则其中一个线程所做的更改将被覆盖。

于 2013-06-19T06:03:48.257 回答
1

可能会让你感兴趣。

你可以为你的类做这样的事情Employee(简化代码只有一个实例变量):

public final class Employee
    implements Frozen<Builder>
{
    private final int salary;

    private Employee(Builder builder)
    {
        salary = builder.salary;
    }

    public static Builder newBuilder()
    {
        return new Builder();
    }

    @Override
    public Builder thaw()
    {
        return new Builder(this);
    }

    public static final class Builder
        implements Thawed<Employee>
    {
        private int salary;

        private Builder()
        {
        }

        private Builder(Employee employee)
        {
            salary = employee.salary;
        }

        public Builder withSalary(int salary)
        {
            this.salary = salary;
            return this;
        }

        @Override
        public Employee freeze()
        {
            return new Employee(this);
        }
    }
}

这样,要修改缓存,您将:

Employee victim = map.get(100);
map.put(100, victim.thaw().withSalary(whatever).freeze());

这是一个完全原子操作。

于 2013-06-19T04:39:37.663 回答
0

如果另一个节点有可能更新您的节点正在使用的数据,那么使用 put() 将覆盖另一个节点所做的更改。通常这是不受欢迎的行为,因为它会导致数据丢失和数据状态不一致。

看看IMap.replace()方法和其他ConcurrentMap相关方法。如果replace()失败,那么您将面临更改冲突。在这种情况下,您应该再次尝试:

  1. 从榛树重读条目
  2. 更新它的字段
  3. 用替换保存到榛树

在一些失败的尝试之后,您可以将 StorageException 抛出到上层。

于 2016-06-15T23:54:56.227 回答
0

您应该在地图条目上使用 tryLock :

    long timeout = 60;  // Define your own timeout 
    if (mapEmployees.tryLock(100, timeout, TimeUnits.SECONDS)){
       try {
          Employee emp1 = mapEmployees.get(100);
          emp1.setAge(30);
          emp1.setSex(“F”);
          emp1.setSalary(5000);
          mapEmployees.put(100, emp1);
       } finally {
           mapEmployees.unlock(100);
       }
   }else{
      // do something else like log.warn(...) 
   }

请参阅:https ://docs.hazelcast.com/imdg/4.2/data-structures/fencedlock#releasing-locks-with-trylock-timeout

于 2021-09-29T14:22:47.197 回答