如何在grails中缓存(整个表或Domain.list()方法的结果)?

时间:2014-10-20 10:13:01

标签: hibernate grails caching

我有一个小表SYMBOLS,用于填充ui的下拉列表。由于此表主要包含静态数据,因此我想缓存其内容。

我的问题是,每次调用方法Symbol.list()时,都会导致数据库执行查询。

域类:

package com.perseus.ui.model

class Symbol implements Serializable, Comparable<Symbol> {

private static final long serialVersionUID = 1L;

String exchange
String symbol
String description
int index

static constraints = {
    exchange(nullable:false, blank: false)
    symbol(nullable:false, blank: false)
    description(nullable:false, blank: false)
}

static mapping = {
    id composite: ['exchange', 'symbol']
    table 'Symbols'
    cache 'read-only'
}

String toString() {
    return description
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
            + ((exchange == null) ? 0 : exchange.hashCode());
    result = prime * result + ((symbol == null) ? 0 : symbol.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Symbol other = (Symbol) obj;
    if (exchange == null) {
        if (other.exchange != null)
            return false;
    } else if (!exchange.equals(other.exchange))
        return false;
    if (symbol == null) {
        if (other.symbol != null)
            return false;
    } else if (!symbol.equals(other.symbol))
        return false;
    return true;
}

@Override
public int compareTo(Symbol o) {
    int result = 0
    if(this.index)
        result = -1
    else if(o.index) {
        result = 1
    } else {
        result = this.symbol.compareTo(o.symbol)
    }
    return result;
}


}

resources.groovy

// Place your Spring DSL code here
beans = {
xmlns cache: 'http://www.springframework.org/schema/cache'
xmlns aop: 'http://www.springframework.org/schema/aop'

importBeans('classpath:config/beans.xml')

cache.'advice'(id: 'symbolCacheAdvice',
        'cache-manager': 'grailsCacheManager') {
        caching(cache: 'symbols') {
            cacheable(method: 'list')
        }
    }

aop.config {
    advisor('advice-ref': 'symbolCacheAdvice',
        pointcut: 'execution(* com.perseus.ui.model.Symbol.*(..))')
}

}

UI元素:<g:select name="symbol" from="${Symbol.list(readOnly: true)}" optionKey="symbol" />

我尝试过以下选项,但似乎没有一个可用:

  1. Hibernate二级缓存:缓存对象,但Symbol.list()始终访问数据库。
  2. 启用查询缓存:没有帮助
  3. Marked Symbols.list()方法@Cachable:令人惊讶的是,即使这样也行不通。请参阅resources.groovy。
  4. 我相信这是非常常见的用例,实现这个的最佳方法是什么?一个显而易见的解决方案是手动缓存它,但这听起来并不好。

1 个答案:

答案 0 :(得分:4)

一般情况下,避免对GORM查询结果使用缓存插件 - Hibernate的第一级和第二级缓存非常可靠,并且对过时数据有抵抗力,因为当这些结果可能受到更改影响时,它们会刷新缓存数据。但是如果您直接使用Ehcache,或者像Spring Cache或Grails插件这样的包装器API,您必须知道何时使数据无效,这可能是一个难题。

如果您计划仅通过list()方法访问缓存数据,这有意义,因为它将全部在内存中,那么您需要一个使用查询缓存的变体,并且必须在DataSource.groovy中:

hibernate {
   cache.use_second_level_cache = true
   cache.use_query_cache = true
   ...
}

list()没有缓存选项,您可以运行等效条件查询:

def symbols = Symbol.createCriteria().list {
   cache true
}

如果要按ID访问项目,请运行查询以获取所有ID,然后在启动时循环访问,并为每个ID调用Symbol.get(id)。单个实例缓存在自己的缓存中,而不是缓存在查询缓存中,因此它们不太可能在早期失效。

另请注意,您需要配置底层缓存实现并配置缓存大小,内存中的元素,溢出到磁盘等.Ehcache中的默认TTL为120秒 - 仅为2分钟。但是如果您很少或从不编辑/创建/删除这些,那么只要您愿意,就可以缓存。