2011-10-27 32 views
17

Tôi có yêu cầu trong đó chúng tôi đang tải dữ liệu tĩnh từ cơ sở dữ liệu để sử dụng trong một ứng dụng Java. Bất kỳ cơ chế bộ nhớ đệm nên có các chức năng sau:Giá trị tải trước cho Bộ nhớ đệm ổi

  • tải tất cả các dữ liệu tĩnh từ cơ sở dữ liệu (một lần nạp, dữ liệu này sẽ không thay đổi)
  • tải dữ liệu mới từ cơ sở dữ liệu (dữ liệu hiện diện trong cơ sở dữ liệu tại start- lên sẽ không thay đổi nhưng có thể thêm dữ liệu mới)

Tải chậm tất cả dữ liệu không phải là tùy chọn vì ứng dụng sẽ được triển khai với nhiều cơ sở dữ liệu. Tải dữ liệu chậm sẽ làm cho yêu cầu đầu tiên cho một phần tử cụ thể quá chậm khi ứng dụng ở một vùng khác với cơ sở dữ liệu.

Tôi đã sử dụng API MapMaker ở ổi với thành công nhưng hiện tại chúng tôi đang nâng cấp lên bản phát hành mới nhất và dường như tôi không thể tìm thấy cùng chức năng trong API CacheBuilder; Tôi dường như không thể tìm thấy cách tải dữ liệu một cách rõ ràng khi khởi động.

Một cách là tải tất cả các khóa từ cơ sở dữ liệu và tải chúng qua Cache riêng lẻ. Điều này sẽ làm việc nhưng sẽ dẫn đến N + 1 các cuộc gọi đến cơ sở dữ liệu, mà không phải là khá hiệu quả giải pháp tôi đang tìm kiếm.

public void loadData(){ 
    List<String> keys = getAllKeys(); 
    for(String s : keys) 
     cache.get(s); 
} 

Hoặc giải pháp khác là sử dụng bản ConcurrentHashMap và xử lý tất cả các chủ đề và mục bị thiếu? Tôi không muốn làm điều này vì API MapMaker và CacheBuilder cung cấp khóa chủ đề dựa trên khóa miễn phí mà không cần phải cung cấp thử nghiệm bổ sung. Tôi cũng khá chắc chắn việc triển khai MapMaker/CacheBuilder sẽ có một số hiệu quả mà tôi không biết/không có thời gian để điều tra.

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(); 
    } 
} 

Có ai nghĩ giải pháp tốt hơn cho hai yêu cầu của tôi không?


Feature Request

Tôi không nghĩ rằng trước khi tải một bộ nhớ cache là một yêu cầu phổ biến, vì vậy nó sẽ được tốt đẹp nếu CacheBuilder cung cấp một tùy chọn cấu hình trước để tải bộ nhớ cache . Tôi nghĩ cung cấp một giao diện (giống như CacheLoader) mà sẽ cư trú trong bộ nhớ cache lúc khởi động sẽ là một giải pháp lý tưởng, chẳng hạn như:

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); 
    } 

}); 

Triển khai này sẽ cho phép Cache được điền sẵn với tất cả các phần tử có liên quan các đối tượng, trong khi vẫn giữ CustomConcurrentHashMap bên dưới không hiển thị với thế giới bên ngoài.

+0

Thêm yêu cầu tính năng vào danh sách các vấn đề về Ổi. –

+1

Đã thêm (số 775) – Richard

+1

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

Trả lời

3

Tôi muốn tải tất cả dữ liệu tĩnh từ DB và lưu trữ nó trong Cache bằng cách sử dụng cache.asMap().put(key, value) ([Guava 10.0.1 cho phép ghi hoạt động trên chế độ xem Cache.asMap()] [1]).

Tất nhiên, dữ liệu tĩnh này có thể bị đuổi, nếu bộ nhớ cache của bạn được cấu hình để đuổi mục ...

Các CachePopulator ý tưởng thú vị.

+1

Điều đó có hiệu quả, nhưng tôi buộc phải sử dụng Guava 10.0.0, sử dụng ComputingCache $ CacheAsMap thực hiện mà ném một UnsupportedOperationException nếu bất kỳ phương thức sửa đổi nào được gọi. Lý tưởng nhất tôi sẽ nâng cấp nhưng đó không phải là một lựa chọn tại thời điểm – Richard

+3

Vâng, 10.0.1 là một bản sửa lỗi nhỏ có mục tiêu là để cho phép cache.asMap(). Put(). Nếu bạn không thể thực hiện một bản nâng cấp nhỏ như vậy, tôi đoán bạn là bánh mì nướng bây giờ ... –

+2

Cảm ơn sự lạc quan của bạn :) – Richard

6

Trong ngắn hạn, tôi chỉ sử dụng Cache.asMap().putAll(Map<K, V>).

Sau khi phát hành xong 11ava, bạn có thể sử dụng Cache.getAll(Iterable<K>), sẽ phát hành một yêu cầu hàng loạt cho tất cả các thành phần vắng mặt.

+10

Cache.getAll (Iterable ) không phát hành một yêu cầu số lượng lớn cho các yếu tố vắng mặt. Theo API, nó sẽ phát hành một cuộc gọi duy nhất cho tất cả các phím được cung cấp, trừ khi overriden. Vui lòng xem http://code.google.com/p/guava-libraries/issues/detail?can=2&q=775&colspec=ID%20Type%20Status%20Milestone%20Summary&id=775 để thảo luận về điều này – Richard

Các vấn đề liên quan