【问题标题】:Implements save (or commit) and rollback methods to a Map实现 Map 的保存(或提交)和回滚方法
【发布时间】:2012-12-05 01:25:34
【问题描述】:

我正在寻找一种快速便捷的方法来将 save() 和 rollback() 添加到标准 Map。假设我有一个表类的对象“表”,它又具有一个名为“行”的私有映射。我想要实现的是一种 fast 并且没有内存浪费的 Row 方法来执行以下操作:

row = new Row();
table.addRow(row).setValue("col1", "foo").setValue("col2", "bar").save();
row.setValue("col2", "beer");
System.out.println(table.getRows()); // 1. col1=foo, col2=bar

row.save();
System.out.println(table.getRows()); // 1. col1=foo, col2=beer

实际上,我的设计很简单:当调用 addRow() 时,我 put() 地图内的行;没有缓冲区,没有临时元素;我只是将整个 Row 实例传递给 rows 集合。但我需要一种快速的方法,并且(如果可能的话)避免重复行。

有什么想法吗?

【问题讨论】:

    标签: java collections commit object-persistence


    【解决方案1】:
    • 在自定义 Map 类中保留两个地图字段, originalMaptemporaryMap
    • 读操作委托给originalMap,写操作委托给temporaryMap
    • rollback() 浅拷贝 originalMaptemporaryMapcommit() 反之亦然。由于永远不会克隆键和值,因此只保留引用并且不会“浪费”内存

    package com.example;
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    import lombok.NonNull;
    import lombok.ToString;
    
    @ToString
    public class TransactionalMap<K, V> implements Map<K, V> {
      
      private Map<K, V> originalMap;
      private Map<K, V> temporaryMap;
      
      public TransactionalMap() {
        this(new HashMap<>());
      }
      
      public TransactionalMap(@NonNull Map<K, V> impl) {
        if (impl instanceof TransactionalMap) {
          throw new IllegalArgumentException("Must provide valid implementation instance");
        }
        this.originalMap = new HashMap<>(impl);
        this.temporaryMap = new HashMap<>(originalMap);
      }
    
      @Override
      public int size() {
        return originalMap.size();
      }
    
      @Override
      public boolean isEmpty() {
        return originalMap.isEmpty();
      }
    
      @Override
      public boolean containsKey(Object key) {
        return originalMap.containsKey(key);
      }
    
      @Override
      public boolean containsValue(Object value) {
        return originalMap.containsValue(value);
      }
    
      @Override
      public V get(Object key) {
        return originalMap.get(key);
      }
    
      @Override
      public V put(K key, V value) {
        return temporaryMap.put(key, value);
      }
    
      @Override
      public V remove(Object key) {
        return temporaryMap.remove(key);
      }
    
      @Override
      public void putAll(Map<? extends K, ? extends V> m) {
        temporaryMap.putAll(m);
      }
    
      @Override
      public void clear() {
        temporaryMap.clear();
      }
    
      @Override
      public Set<K> keySet() {
        return originalMap.keySet();
      }
    
      @Override
      public Collection<V> values() {
        return originalMap.values();
      }
    
      @Override
      public Set<Entry<K, V>> entrySet() {
        return originalMap.entrySet();
      }
      
      private void sync(Map<K, V> src, Map<K, V> tgt) {
        tgt.putAll(src);
        tgt.forEach((k, v) -> {
          if (!src.containsKey(k)) tgt.remove(k);
        });
      }
      
      public void commit() {
        sync(temporaryMap, originalMap);
      }
      
      public void rollback() {
        sync(originalMap, temporaryMap);
      }
    
    }
    

    使用lombok 生成样板代码

    【讨论】:

      【解决方案2】:

      这听起来太像“我想在内存中拥有新旧值,但我不想在内存中拥有新旧值”。

      选项:

      a) 所有added 元素的映射,保存时执行putAll

      b) 你的地图,而不是&lt;ClassKey, ClassValue&gt;,拥有&lt;ClassKey, ClassValue2&gt;Value2 持有ClassValue 的两项,新的和旧的实例。在save,您将新的(如果有的话)传递给旧的。仅当您更改每个“事务”中的大部分条目时,它才会有用。

      没有提到删除元素的问题,它会给你带来更多的乐趣。使用选项 2,您可以将布尔值设置为 Value2,使用选项 a 您将需要更多解决方法。

      【讨论】:

      • 这听起来太像“我想在内存中拥有新旧值,但我不想在内存中拥有新旧值” ok I明白了;)
      • 哦,最好的选择:使用一些已经实现事务的框架。现在的数据库很便宜,也许你可以找到一些实现这一点的 FOSS 库。
      【解决方案3】:

      我想要实现的是一种快速且没有内存浪费的方法 让 Row 执行以下操作:

      你会浪费内存,因为你需要在某个地方保持“回滚”,以防它在途中失败。这就是数据库处理这些类型的事情的方式。

      现在要获得您想要的功能,您需要实现自己的自定义事务逻辑,这将允许您正确回滚/保留对地图的更改。现在,在此交易中,您需要跟踪交易期间发生的所有事情。这是因为您将对原始地图进行临时写入,而事务处理,随后您将需要能够从失败的持久/更新中恢复。

      为避免行重复,HashMap 已经可以让您摆脱这个问题。假设您正确实现了一个哈希函数,当两个对象生成相同的代码并因此在哈希方面“潜在”而不是绝对相等时,该函数会正确报告。

      【讨论】:

        猜你喜欢
        • 2011-07-23
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 2011-01-09
        • 1970-01-01
        • 2013-09-14
        • 1970-01-01
        • 2014-02-23
        相关资源
        最近更新 更多