2011-10-27 2 views
17

Java 응용 프로그램에서 사용할 정적 데이터를 데이터베이스에서로드해야하는 경우가 있습니다. 시작 -에 데이터베이스 (데이터베이스에 존재하는 데이터로부터 데이터베이스에서 모든 정적 데이터 (한 번로드는,이 데이터가 변경되지 않습니다)Guava 캐시에 대한 사전로드 값

  • 로드
  • 로드 새로운 데이터 : 모든 캐싱 메커니즘은 다음과 같은 기능을 가지고 있어야 변경 사항은 변경되지 않지만 새 데이터를 추가 할 수 있음)

응용 프로그램이 여러 지리적 위치에 배포되고 단일 데이터베이스와 통신해야하므로 모든 데이터의 지연로드가 옵션이 아닙니다. 데이터를 게으르게로드하면 응용 프로그램이 데이터베이스와 다른 영역에있는 경우 특정 요소에 대한 첫 번째 요청이 너무 느려집니다.

Guava에서 MapMaker API를 성공적으로 사용해 왔지만 현재 최신 버전으로 업그레이드하고 있으며 CacheBuilder API에서 동일한 기능을 찾을 수 없습니다. 시작시 모든 데이터를로드하는 깨끗한 방법을 찾지 못하는 것 같습니다.

한 가지 방법은 데이터베이스에서 모든 키를로드하고 캐시를 통해 키를 개별적으로로드하는 것입니다. 이것은 작동하지만 데이터베이스에 대한 N + 1 호출을 발생시킬 수 있습니다. 이는 내가 찾고있는 효율적인 솔루션이 아닙니다.

또는 다른 해결책은 ConcurrentHashMap 구현을 사용하고 모든 스레드와 누락 된 항목을 직접 처리하는 것입니다. 필자는 MapMaker와 CacheBuilder API가 여분의 테스트를 제공 할 필요없이 키 기반 스레드 잠금을 무료로 제공하므로이 작업에 열중하지 않습니다. 또한 MapMaker/CacheBuilder 구현에 대해 내가 알지 못하는/조사 할 시간이없는 몇 가지 효율성이 있음을 확신합니다.

public Element get(String key){ 
    Lock lock = getObjectLock(key); 
    lock.lock(); 
    try{ 
     Element ret = map.get(key) 
     if(ret == null){ 
      ret = getElement(key); // database call 
      map.put(key, e); 
     } 
     return ret; 
    }finally { 
     lock.unlock(); 
    } 
} 

누구나 내 두 가지 요구 사항에 대한 더 나은 해결책을 생각할 수 있습니까?


기능 요청

나는 생각하지 않는다 미리로드 캐시하는 것은 드문 요구 사항이므로, CacheBuilder 캐시를 미리로드 할 수있는 구성 옵션을 제공하면 좋을 것입니다 .

CacheBuilder.newBuilder().populate(new CachePopulator<String, Element>(){ 

    @Override 
    public Map<String, Element> populate() throws Exception { 
     return getAllElements(); 
    } 

}).build(new CacheLoader<String, Element>(){ 

    @Override 
    public Element load(String key) throws Exception {  
     return getElement(key); 
    } 

}); 

이 구현은 캐시가 모든 관련 요소가 미리 입력되어있을 수 있습니다 것 : 나는 같은 이상적인 솔루션이 될 것입니다 시작시 캐시를 채 웁니다 (많은 CacheLoader 같은) 인터페이스를 제공 생각 기본 CustomConcurrentHashMap을 외부 세계에 보이지 않게 유지합니다.

+0

구아바 문제 목록에 기능 요청을 추가하십시오. –

+1

추가됨 (문제 775) – Richard

+1

http://code.google.com/p/guava-libraries/issues/detail?id=775 –

답변

3

DB에서 모든 정적 데이터를로드하고 cache.asMap().put(key, value) ([Guava 10.0.1은 Cache.asMap()보기에서 쓰기 작업 허용] [1])을 사용하여 캐시에 저장합니다. 캐시는 항목을 퇴거하도록 구성된 경우 물론

이 정적 데이터는

CachePopulator 아이디어는 재미있다 ..., 퇴거받을 수 있습니다.

+1

그래도 작동하지만 Guava 10.0.0을 사용해야합니다. ComputingCache $ CacheAsMap 구현. 수정 메소드가 불려 가면 (자) UnsupportedOperationException를 Throw합니다. 이상적으로 나는 업그레이드 할 것이지만 지금은 옵션이 아닙니다. – Richard

+3

글쎄, 10.0.1은 cache.asMap(). put()을 다시 허용하는 작은 버그 수정 릴리즈였습니다. 그런 작은 업그레이드를 할 수 없다면, 지금은 토스트 일 것 같아요. –

+2

낙천주의에 감사드립니다. – Richard

6

단기간에 나는 Cache.asMap().putAll(Map<K, V>)을 사용합니다.

Guava 11.0이 출시되면 Cache.getAll(Iterable<K>)을 사용하면 부재 구성 요소에 대해 대량 요청을 하나씩 처리 할 수 ​​있습니다.

+10

Cache.getAll (Iterable )은 결석 한 요소에 대해 대량 요청을 하나도 발행하지 않습니다. API에 따라 오버라이드 (override)되지 않는 한, 제공된 모든 키에 대해 단일 호출을 발행합니다. 이에 대한 토론은 http://code.google.com/p/guava-libraries/issues/detail?can=2&q=775&colspec=ID%20Type%20Status%20Milestone%20Summary&id=775를 참조하십시오. – Richard