我正在实现一个基于Spring MVC的Web应用程序,其中我添加了缓存,但是当更改应用于底层数据库时,现在在如何操作缓存方面遇到了问题。
我一直在研究Ehcache(http://ehcache.org/documentation)提供的文档,但没有找到任何好的例子来解决我的问题。
假设我有一个DAO类,我选择在两个返回对象列表的方法上应用缓存(不可编译的伪代码):
@Repository
public class MyEntityDao {
@Autowired
DataSource ds;
@Autowired
EhCacheCacheManager cacheManager;
@Autowired
CacheKeyGenerator keyGenerator;
@Cacheable("myEntityCache")
public List<MyEntity> findByFieldAlpha(String fieldAlpha) {
return ds.query("select * from MyEntity where fieldAlpha = #fieldAlpha").execute();
}
@Cacheable("myEntityCache")
public List<MyEntity> findByFieldBeta(String fieldBeta) {
return ds.query("select * from MyEntity where fieldBeta = #fieldBeta").execute();
}
public void deleteByFieldAlpha(String fieldAlpha) {
ds.query("delete from MyEntity where fieldAlpha = #fieldAlpha").execute();
}
public void deleteByFieldBeta(String fieldBeta) {
ds.query("delete from MyEntity where fieldBeta = #fieldBeta").execute();
}
public void store(MyEntity myEntity) {
ds.insert(myEntity).execute();
}
}
我正在使用自定义KeyGenerator,因此我知道在调用方法时如何生成键:
public class CacheKeyGenerator implements KeyGenerator {
@Override
public Object generate(final Object target, final Method method, final Object... params) {
return generateCacheKey(method.getName(), params);
}
public String generateCacheKey(final String methodName, final Object... params) {
StringBuilder key = new StringBuilder();
key.append(methodName);
for (Object o : params) {
key.append("_").append(o.toString());
}
return key.toString();
}
}
我需要解决的一个明显问题是,在将数据添加或移除到底层数据库时,我应该如何实现缓存修改策略。
对于商店方法,我发现问题很容易解决:
...
public void store(MyEntity myEntity) {
boolean success = ds.insert(myEntity).execute();
if (success) {
Cache cache = cacheManager.getCache("myEntityCache")
String keyFieldAlpha = keyGenerator.generateCacheKey("findByFieldAlpha", myEntity.getFieldAlpha());
List cacheListFieldAlpha = (List) cache.get(keyFieldAlpha).getObjectValue();
cacheListFieldAlpha.add(myEntity);
String keyFieldBeta = keyGenerator.generateCacheKey("findByFieldBeta", myEntity.getFieldBeta());
List cacheListFieldBeta = (List) cache.get(keyFieldBeta).getObjectValue();
cacheListFieldBeta.add(myEntity);
}
}
但是对于删除方法来说,事情要复杂得多。
这是我到目前为止提出的一个实现,但它似乎远比它应该更复杂(代价高昂)。如果我的设计模式是正确的,或者是否应该以任何其他方式解决我的问题,任何人都有任何有价值的输入?
public void deleteByFieldAlpha(String fieldAlpha) {
List<MyEntity> myEntititesToBeDeleted = this.findByFieldAlpha(fieldAlpha);
boolean success = ds.query("delete from MyEntity where fieldAlpha = #fieldAlpha").execute();
if (success) {
Cache cache = cacheManager.getCache("myEntityCache")
String keyFieldAlpha = keyGenerator.generateCacheKey("findByFieldAlpha", fieldAlpha);
cache.remove(keyFieldAlpha);
for (MyEntity myEntity : myEntititesToBeDeleted) {
String keyFieldBeta = keyGenerator.generateCacheKey("findByFieldBeta", myEntity.getFieldBeta());
List cacheListFieldBeta = (List) cache.get(keyFieldBeta).getObjectValue();
cacheListFieldBeta.remove(myEntity);
}
}
}
也许这是解决问题的正确方法?我没有偶然发现解决这些问题的任何食谱,所以我最好在这里猜测。
答案 0 :(得分:0)
我会告诉你我的意见。它似乎(几乎)是正确的方法。我认为在删除操作之后你应该清空所有缓存并重新开始。通常,在数据更改操作之后,缓存被重置。这是因为表连接而完成的。似乎不是你的情况,因为你只有两个查询而且没有连接,但通常会清理并重新启动缓存。这样,在“fieldAlfa”中进行更改后,您无需扫描引用“fieldBeta”的缓存。希望从中获得一些帮助。 顺便说一句,MyBatis也是这样。
答案 1 :(得分:0)
使用Ehcache search API,可能在运算符中对你来说很有用。