简体   繁体   English

JPA:仅当结果集不为空时才缓存查询

[英]JPA: cache queries only if resultset is not empty

I am on JPA 2.1 + Hibernate + EHCache .我在JPA 2.1 + Hibernate + EHCache 上

Here is my named query (the query code is not relevant):这是我的命名查询(查询代码不相关):

List<MyEntity> list = getEntityManager()
    .createNamedQuery("my-query-id", MyEntity.class))
    .setHint(QueryHints.CACHEABLE,    true)
    .setHint(QueryHints.CACHE_REGION, "my-query-region")
    .setParameter("my-query-param", "my-param-value")
    .setMaxResults(1)
    .getResultList();

if (list.isEmpty()) {
    log.warn("No data found.");
    return null;
}

return list;

The goal I wish to achieve is to cache query result only if its result is non empty .我希望实现的目标是仅在结果非空时才缓存查询结果。

I am sure, beacause I inspected it by hibernate logging at a trace level, that empty result set is cached anyway.我敢肯定,因为我通过跟踪级别的休眠日志记录检查了它,无论如何都会缓存该空结果集。

Any suggestion would be appreciated.任何建议将不胜感激。

Regards!问候!

I found a solution by writing an EHCache Decorator like follow:我通过编写一个EHCache 装饰器找到了一个解决方案,如下所示:

EHCache XML configuration fragment EHCache XML 配置片段

<cache name="my-queries-region"
       maxEntriesLocalHeap="50000"
       eternal="false"
       timeToLiveSeconds="14400">

    <persistence strategy="none"/>

    <!-- https://www.ehcache.org/ehcache.xml -->

    <cacheDecoratorFactory
        class="com.example.JpaCacheDecoratorNotEmptyQueryFactory" />
</cache>

Decorator factory implementation装饰工厂实现

package com.example;

import net.sf.ehcache.Ehcache;
import net.sf.ehcache.constructs.CacheDecoratorFactory;

import java.util.Properties;

public class JpaCacheDecoratorNotEmptyQueryFactory extends CacheDecoratorFactory {

    @Override
    public Ehcache createDecoratedEhcache(Ehcache cache, Properties properties) {
        return new JpaCacheDecoratorNotEmptyQueryDecorator(cache);
    }

    @Override
    public Ehcache createDefaultDecoratedEhcache(Ehcache cache, Properties properties) {
        return new JpaCacheDecoratorNotEmptyQueryDecorator(cache);
    }
}

Decorator implementation装饰器实现

package com.example;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.constructs.EhcacheDecoratorAdapter;
import org.hibernate.cache.internal.QueryResultsCacheImpl;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

@Slf4j
public class JpaCacheDecoratorNotEmptyQueryDecorator extends EhcacheDecoratorAdapter {

    private final Field resultsField;

    @SneakyThrows
    @SuppressWarnings("rawtypes")
    protected boolean canCache(Element element) {
        boolean cacheable = true;
        Object  value     = element.getObjectValue();

        if (value instanceof QueryResultsCacheImpl.CacheItem) {
            List results = (List)resultsField.get(value);
            cacheable    = !results.isEmpty();
        }

        if (!cacheable) {
            if (log.isDebugEnabled()) {
                log.debug("Query not cacheable due to empty result set.");
            }
        }

        return false;
    }

    protected boolean canCache(Collection<Element> elements) {
        for (Element element: elements) {
            if (!canCache(element)) {
                return false;
            }
        }

        return true;
    }

    @SneakyThrows
    public JpaCacheDecoratorNotEmptyQueryDecorator(Ehcache underlyingCache) {
        super(underlyingCache);

        resultsField = QueryResultsCacheImpl
            .CacheItem
            .class
            .getDeclaredField("results");

        resultsField.setAccessible(true);
    }

    @Override
    public void put(Element element, boolean doNotNotifyCacheReplicators)
        throws IllegalArgumentException,
               IllegalStateException,
               CacheException
    {
        if (canCache(element)) {
            super.put(element, doNotNotifyCacheReplicators);
        }
    }

    @Override
    public void put(Element element)
        throws IllegalArgumentException,
               IllegalStateException,
               CacheException
    {
        if (canCache(element)) {
            super.put(element);
        }
    }

    @Override
    public void putAll(Collection<Element> elements)
        throws IllegalArgumentException,
               IllegalStateException,
               CacheException
    {
        if (canCache(elements)) {
            super.putAll(elements);
        }
    }

    @Override
    public void putQuiet(Element element)
        throws IllegalArgumentException,
               IllegalStateException,
               CacheException
    {
        if (canCache(element)) {
            super.putQuiet(element);
        }
    }

    @Override
    public void putWithWriter(Element element)
        throws IllegalArgumentException,
               IllegalStateException,
               CacheException
    {
        if (canCache(element)) {
            super.putWithWriter(element);
        }
    }

    @Override
    public Element putIfAbsent(Element element)
        throws NullPointerException
    {
        if (canCache(element)) {
            return super.putIfAbsent(element);
        } else {
            return null;
        }
    }

    @Override
    public Element putIfAbsent(Element element, boolean doNotNotifyCacheReplicators)
        throws NullPointerException
    {
        if (canCache(element)) {
            return super.putIfAbsent(element, doNotNotifyCacheReplicators);
        } else {
            return null;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM