【问题标题】:Guava CacheLoader MissesGuava CacheLoader 未命中
【发布时间】:2017-06-21 01:21:14
【问题描述】:

我在这里不知所措。

我真的很幸运手动加载/插入 Guava 缓存,但我认为它应该更“线程安全”(通过 CacheLoader)。

当我重构为使用 CacheLoader.load 样式语法时,我的缓存停止工作。现在,每个 get() 都是缓存未命中,并启动对 load() 的调用。

我错过了一些非常简单的东西吗?

缓存:

public class DatabasePropertyCache implements RemovalListener<DatabasePropertyCache.Key, Optional<Object>> {

    //InitializeOnDemand style singleton
    //  http://en.wikipedia.org/wiki/Singleton_pattern#Initialization_On_Demand_Holder_Idiom
    private static class Singleton {
        static DatabasePropertyCache INSTANCE = new DatabasePropertyCache();
    }
    public static DatabasePropertyCache getInstance() {
        return Singleton.INSTANCE;
    }
    private DatabasePropertyCache() {
        logger = Logger.getLogger(DatabasePropertyCache.class);
        cache = CacheBuilder
                    .newBuilder()
                    .expireAfterWrite(24, TimeUnit.HOURS)
                    .removalListener(this)
                    .build( 
                        new CacheLoader<Key, Optional<Object>>() {

                            @Override
                            public Optional<Object> load(Key key) throws Exception {
                                Object propertyValue = [performs a query]
                                return Optional.fromNullable(propertyValue);
                            }
                        });
    }

    private final LoadingCache<Key, Optional<Object>> cache;
    private final Logger logger;

    public void onRemoval(RemovalNotification<Key, Optional<Object>> arg0) {
        if(logger.isDebugEnabled()) {
            logger.debug(String.format("Cached database property expiring %s", arg0.getKey().toString()));
        }
    }

    /**
     * Returns a cached value. If it has never been cache before, it will be fetched from the database.
     * 
     * @param value
     * @param locale
     * @param dataset
     * @return
     */
    public Object getObject(String id, DatabasePropertiesEnum property, Locale locale) {
        Key key = new Key(id, property, locale);

        try {
            return cache.get(key).orNull();
        }
        catch (ExecutionException eex) {
            logger.warn(String.format("Error fetching database property %s", key.toString()), eex);
        }
        return null;
    }

    protected class Key {

        private static final String TOSTRING_TEMPLATE = "DatabasePropertyCache.Key[dataset=%s, locale=%s, property=%s]";

        private String id;
        private DatabasePropertiesEnum property;
        private Locale locale;

        public Key(String id, DatabasePropertiesEnum property, Locale locale) {
            this.id= id;
            this.property = property;
            this.locale = locale;
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder()
                    .append(this.id)
                    .append(this.property)
                    .append(this.locale)
                    .toHashCode();
        }

        public String getId() {
            return id;
        }

        public DatabasePropertiesEnum getProperty() {
            return property;
        }

        public Locale getLocale() {
            return locale;
        }

        @Override
        public String toString() {
            return String.format(TOSTRING_TEMPLATE, id, locale.toString(), property.name());
        }
    }
}

用法:

Object cacheHit = DatabasePropertyCache.getInstance().getObject("some_id", DatabasePropertiesEnum.SOME_KEY, [users current locale]);

【问题讨论】:

    标签: java caching guava


    【解决方案1】:

    Key 类必须正确实现equals()hashcode()

    您可以使用Guava EqualsTester 来测试您的equals 和hashCode:

    【讨论】:

      【解决方案2】:

      看起来您的Key 类需要定义一个equals() 方法。

      【讨论】:

      • 所以是的,我错过了一些非常简单的东西。我们之前的实现使用了一个 int(通过 .hashCode())作为键,因此出现了错误。谢谢!
      猜你喜欢
      • 2013-07-13
      • 2017-04-20
      • 1970-01-01
      • 1970-01-01
      • 2014-05-01
      • 1970-01-01
      • 2017-07-11
      • 1970-01-01
      • 2022-01-13
      相关资源
      最近更新 更多