我有一个小表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" />
我尝试过以下选项,但似乎没有一个可用:
我相信这是非常常见的用例,实现这个的最佳方法是什么?一个显而易见的解决方案是手动缓存它,但这听起来并不好。
答案 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分钟。但是如果您很少或从不编辑/创建/删除这些,那么只要您愿意,就可以缓存。