JPA:仅当resultset不为空时缓存查询



我在JPA 2.1Hibernate ++EHCache.

这是我的命名查询(查询代码不相关):

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;

我希望实现的目标是缓存查询结果,只有当它的结果是非空.

我确信,因为我在跟踪级别上通过hibernate日志检查了它,无论如何,空结果集都是缓存的。

如有任何建议,不胜感激。

问候!

我找到了一个解决方案,通过编写EHCache装饰器如:

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>

装饰器工厂实现

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

装饰实施

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

最新更新