Guava - кэширование таблицы и использование методов get для этого кеша - PullRequest
0 голосов
/ 30 мая 2018

Я ранее реализовал кэширование в своем приложении, которое будет использоваться с тремя отдельными методами get.Эти методы получения: getAllProfiles(), getProfilesByID() и getProfileByFields().Из-за этого мой код выглядит следующим образом:

private LoadingCache<int[], List<Profile>> loadingCache = CacheBuilder.newBuilder()
            .refreshAfterWrite(5, TimeUnit.MINUTES)
            .expireAfterAccess(5, TimeUnit.MINUTES)
            .maximumSize(100).build(
                    new CacheLoader<int[] ids, List<Profile>>() {
                        @Override
                        public List load(int[] ids) throws Exception {
                            return profileDAO.getProfilesById(ids);
                        }
                    }
            );

    private LoadingCache<Integer, List<Profile>> loadingCache2 = CacheBuilder.newBuilder()
            .refreshAfterWrite(5, TimeUnit.MINUTES)
            .expireAfterAccess(5, TimeUnit.MINUTES)
            .maximumSize(100).build(
                    new CacheLoader<Integer, List<Profile>>() {

                        @Override
                        public List<Profile> load(Integer size) throws Exception {
                            return profileDAO.getAllProfiles(size);
                        }
                    }
            );

    private LoadingCache<Profile, List<Profile>> loadingCache3 = CacheBuilder.newBuilder()
            .refreshAfterWrite(5, TimeUnit.MINUTES)
            .expireAfterAccess(5, TimeUnit.MINUTES)
            .maximumSize(100).build(
                    new CacheLoader<Profile, List<Profile>>() {
                        @Override
                        public List<Profile> load(Profile profile) throws Exception {
                            return profileDAO.getProfileByFields(profile);
                        }
                    }
            );

public ProfileManagerImpl(ProfileDAO profileDAO) {
        this.profileDAO = profileDAO;
    }


public List<Profile> getAllProfiles(Integer size) throws Exception {
    return loadingCache2.get(size);
}

public List<Profile> getProfilesById(int[] idArray) throws Exception {
        return loadingCache.get(idArray);
    }

public List<Profile> getProfileByFields(Profile profile) throws Exception {
        return loadingCache3.get(profile);
    }

Однако, чтобы упростить свою работу, мне нужно создать один кэш, который создается при запуске, используя getAllProfiles() для всей таблицы.Все три метода затем будут использовать этот один кеш для работы.

Я думаю, что я могу просто повторно использовать код для loadCache2, чтобы сначала создать кеш:

private LoadingCache<Integer, List<Profile>> loadingCache2 = CacheBuilder.newBuilder()
            .refreshAfterWrite(5, TimeUnit.MINUTES)
            .expireAfterAccess(5, TimeUnit.MINUTES)
            .maximumSize(100).build(
                    new CacheLoader<Integer, List<Profile>>() {

                        @Override
                        public List<Profile> load(Integer size) throws Exception {
                            return profileDAO.getAllProfiles(size);
                        }
                    }
            );

и передатьnull для размера, поэтому оператор SQL в DAO будет «SELECT * FROM Profiles».Проблема придет от других методов;Я понятия не имею, как указать эти методы для этого кэша, учитывая различные входные требования.Кто-нибудь делал что-то подобное ранее?

Редактировать:

Как предложил Луи Вассерман, я делаю один объект Cache, который принимает Object в качестве универсального ключа.Оттуда сервис должен использовать оператор if, чтобы определить тип входного объекта, и использовать соответствующий метод для извлечения содержимого кэша, в зависимости от используемого метода.

На данный момент, однако, он терпит неудачуна getAllProfiles, за исключением нулевого указателя, поэтому мне нужно это выяснить.

Исходя из приведенного ниже кода, похоже, я на правильном пути?Я использую Cache, а не LoadingCache для этого объекта:

public Cache<Object, List<Profile>> cache =
            CacheBuilder.newBuilder()
            .refreshAfterWrite(5, TimeUnit.MINUTES)
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .build(new CacheLoader<Object, List<Profile>>() {
                @Override
                public List<Profile> load(Object k) throws Exception {
                    if (k instanceof Integer) {
                        return profileDAO.getAllProfiles((Integer) k);
                    }
                    else if (k instanceof int[]) {
                        return profileDAO.getMultipleProfiles((int[]) k);
                    }
                    else if (k instanceof Profile)
                        return profileDAO.getProfileByFields((Profile) k);
                }
            });



public List<Profile> getAllProfiles(Integer size) throws Exception {
        return cache.getIfPresent(size);
    }

1 Ответ

0 голосов
/ 30 мая 2018

Я думаю, что есть некоторое неправильное использование концепции кеша.Кэш будет загружен, только когда он не найдет элементы, поэтому, создав кеш, ключ которого является списком, вы сводите на нет концепцию кэша (поскольку список является объектом, и если вы не передадите тот же список, вы никогда не будете повторно использоватьзначения, таким образом, всегда загружаются из БД и не используют кеш).Я думаю, вам нужно использовать только один кэш, использовать идентификатор в качестве ключа (как предложил @Ben Manes) и обернуть его вспомогательными методами (этот код не был проверен, поэтому попробуйте с осторожностью).

/** This is whatever class you intended to put the cache in anyways */
public class CacheWrapper {
    private LoadingCache<Integer, Profile> loadingCache;

    public CacheWrapper(/* whatever arguments the class needs*/) {
        loadingCache = CacheBuilder.newBuilder()
            .refreshAfterWrite(5, TimeUnit.MINUTES)
            .expireAfterAccess(5, TimeUnit.MINUTES)
            .maximumSize(100).build(
                new CacheLoader<Integer, Profile>() {
                    @Override
                    public List<Profile> load(Integer id) throws Exception {
                        return profileDAO.getProfileById(id);
                    }
                }
            );

         // init the cache here
         for (Profile profile : profileDAO.getAllProfiles(null)) {
             loadingCache.put(profile.getId(), profile);
         }    

         /* other construction logic here */
    }

    public List<Profile> getAllProfiles() throws Exception {
        return new ArrayList(loadingCache.asMap().values());
    }

    public List<Profile> getProfilesById(int[] idArray) throws Exception {
        List<Profile> profiles = new ArrayList(idArray.length());

        for(int i = 0; i < idArray.length(); i++) {
            profiles.add(loadingCache.get(idArray[i]));
        }

        return profiles;
    }

    public List<Profile> getProfileByFields(Profile profile) throws Exception {
        List<Profile> profiles = new ArrayList(idArray.length());

        for (Profile cachedProfile : loadingCache.asMap().values()) {
            if (profile.hasEqualFields(cachedProfile)) {
                profiles.add(cachedProfile);
            }
        }

        return profiles;
    }
}

Вы также можете оптимизировать это далее, создав второй кеш с ключом Profile и списком соответствующих профилей в качестве значения, а затем вы можете заменить getProfileByFields тем же способом, который вы сделали - с загрузкой кеша Profiles с аналогичными полями из базы данных.Наконец, следите за тем, как загрузка из кэша создает псевдонимы, поэтому вам нужно быть осторожным с тем, что вы делаете с данными.

Надеюсь, это понятно и поможет в любом случае.

...