5

Java コードでキャッシュされたマップが必要です。マップは DB からロードされ、(マップ内のすべてのデータについて) DB から定期的に再ロードする必要があります。現在、新しいパッケージをインポートできないためです。Google の guava パッケージまたはコード例に既存の関数はありますか?

マップがスレッドセーフとして実装されている方がよいでしょう。でも、シンプルでなくてもOKです。

「LoadingCache」は私が好きなものですが、最初にデータをマップに入れるためのデータ初期化メソッドがありません。そして、マップの有効期限が切れた後、「get」が来るたびにDBに到達する必要があります。

ありがとうございました!


いくつかのサンプル コードがここで役立つ場合があります。

public interface AToBMapper
{

    public static final String DEFAULT_B_NAME = "DEFAULT";

    public String getBForA(final String a);
}

public class AToBMapperImpl implements AToBMapper
{
    private final SomeDAO dao;

    private Map<String, String> cachedMap;

    public AToBMapperImpl(final SomeDAO dao)
    {
        this.dao = dao;
        cachedMap = new HashMap<String, String>();
    }

    public String getBForA(final String a)
    {
        // if the map is not initialized, initialize it with the data
        // if the map is expired, refresh all the data in the map
        // return the mapped B for A (if there is no mapping for A, return the "DEFAULT")
    }

    private Map<String, String> getTheData(final List<String> listOfB)
    {
        Map<String, String> newData = dao.getAToBMapping(listOfB);
    }
}
4

3 に答える 3

1

「LoadingCache」は私が好きなものですが、最初にデータをマップに入れるためのデータ初期化メソッドがありません。

もちろん、そのようなメソッドはあります -拡張するインターフェイスputAll(Map<K, V>)から。メソッドは、指定されたマップからキャッシュにすべてのマッピングをコピーしますCacheLoadingCache

put(K, V)この目的で使用できる同様の方法もあります。

編集:

あなたのコメントに基づいて、あなたはまったく望んLoadingCacheでおらず、すべてのエントリの有効期限を自分で維持していると言えます。使用できるものの簡単な例を次に示します (JDK と Guava のクラスのみ)。

public class AToBMapperImpl implements AToBMapper {
  public static final long EXPIRE_TIME_IN_SECONDS =
      TimeUnit.SECONDS.convert(1, TimeUnit.HOURS); // or whatever
  private final SomeDAO dao;
  private final ConcurrentMap<String, String> cache;
  private final Stopwatch stopwatch;

  public AToBMapperImpl(SomeDAO dao) {
    this.dao = dao;
    stopwatch = new Stopwatch();
    cache = new MapMaker().concurrencyLevel(2).makeMap();
  }

  @Override
  public synchronized String getBForA(final String a) {
    // if the map is not initialized, initialize it with the data
    if (!stopwatch.isRunning()) {
      cache.putAll(getNewCacheContents());
      stopwatch.start();
    }

    // if the map is expired, refresh all the data in the map
    if (stopwatch.elapsedTime(TimeUnit.SECONDS) >= EXPIRE_TIME_IN_SECONDS) {
      cache.clear();
      cache.putAll(getNewCacheContents());
      stopwatch.reset();
    }

    // return the mapped String for A
    // (if there is no mapping for A, return the "DEFAULT")
    return cache.containsKey(a) ? cache.get(a) : new String(DEFAULT_B_NAME);
  }

  private Map<String, String> getNewCacheContents() {
    return getTheData(Arrays.asList("keys", "you", "want", "to", "load"));
  }

  private Map<String, String> getTheData(List<String> listOfB) {
    return dao.getAToBMapping(listOfB);
  }
}
于 2013-03-12T09:58:08.823 に答える
1

@Xaerxess は実行可能なソリューションを提供しましたLoadingCacheが、単一のキー値を持つインスタンスを使用するだけでこれを達成できたと思います。単一のオブジェクトのロードがセット全体と同じくらい高価なプロジェクトに取り組んできたので、シナリオに関するあなたの推論を理解しています。

public class AToBMapperImpl implements AToBMapper {

    private final LoadingCache<Boolean, Map<String, String>> cachedMap;

    public AToBMapperImpl(final SomeDAO dao, final List<String> listOfB) {
        this.cachedMap = CacheBuilder.newBuilder()
                .expireAfterAccess(4, TimeUnit.HOURS)
                .build(new CacheLoader<Boolean, Map<String, String>>() {
                    @Override
                    public Map<String, String> load(Boolean k) throws Exception {
                        return dao.getAToBMapping(listOfB);
                    }
                });
    }

    @Override
    public String getBForA(String a) {
        try {
            Map<String, String> map = cachedMap.get(Boolean.TRUE);
            return map.containsKey(a) ? map.get(a) : DEFAULT_B_NAME;
        } catch (ExecutionException ex) {
            // Do what you need to do on exception.
            throw new RuntimeException(ex.getMessage(), ex);
        }
    }

}

このようにして、キャッシュは単一のエントリにバインドされ、値は目的のマップになります。有効期限の恩恵を受けます。時間の経過とともに変化する可能性がある場合listOfBは、別のサービス メソッドを記述してこれを取得し、キャッシュ ローダーが呼び出す必要がある場合があります。

于 2013-10-07T05:24:50.817 に答える
-1

データの初期化メソッドは必要ありません。初回アクセス時に初期化できます。これを行う方法のサンプルコードは次のとおりです

cachedWhatever = 
    cacheBuilder
    .maximumSize(5)
    .expireAfterAccess(30, TimeUnit.MINUTES)
    .removalListener(new RemovalListener<String, CachedWhatever>() {

        @Override
        public void onRemoval(RemovalNotification<String, CachedMetadata> notification) {
            logger.info("removed");
        }
    })
    .build(new CacheLoader<String, CachedWhatever>(){

            @Override
        public CachedMetadata load(String databaseName) throws Exception {
            logger.info("created");

            return new CachedWhatever();
            }
        });

そしてキャッシュにアクセスした後

cachedWhatever.get([key]);

存在しない場合はキャッシュを作成します

を使用cachedWhatever.invalidate([key]);すると、キーのキャッシュがクリアされます

于 2013-03-12T10:15:12.680 に答える