1

我正在寻找一种快速便捷的方法来将 save() 和 rollback() 添加到标准 Map。假设我有一个表类的对象“表”,它又具有一个名为“行”的私有映射。我想要实现的是一种快速且没有内存浪费的 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() 时,我将行放在地图中;没有缓冲区,没有临时元素;我只是将整个 Row 实例传递给 rows 集合。但我需要一种快速的方法,并且(如果可能的话)避免重复行。

任何的想法?

4

3 回答 3

3

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

选项:

a)所有added元素的地图,当保存时putAll

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

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

于 2012-12-17T22:02:02.077 回答
2

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

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

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

为避免行重复,HashMap 已经将您从该问题中解救出来。假设您正确实现了一个散列函数,该函数在两个对象生成相同代码时正确报告,因此在散列方面“潜在”而不是绝对相等。

于 2012-12-17T21:56:55.527 回答
0
  • 在自定义 Map 类中保留两个地图字段, originalMap并且temporaryMap.
  • 读操作委托给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生成样板代码

于 2021-12-31T05:00:37.767 回答