1

我有一个使用 MyBatis 进行持久性的 Spring 应用程序。我正在使用 ehcache,因为速度对于这个应用程序很重要。我已经设置并配置了 MyBatis 和 Ehcache。我正在使用一个名为“mybatis”的缓存,因为否则为每个实体创建单独的缓存将是荒谬的。

这是我的 ehcache.xml。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="false"
         monitoring="autodetect"
         dynamicConfig="true">

    <diskStore path="java.io.tmpdir" />

    <cache name="mybatis"
           maxBytesLocalHeap="100M"
           maxBytesLocalDisk="1G"
           eternal="false"
           timeToLiveSeconds="0"
           timeToIdleSeconds="0"
           statistics="true"
           overflowToDisk="true"
           memoryStoreEvictionPolicy="LFU">
    </cache>

    <cache name="jersey"
           maxBytesLocalHeap="100M"
           maxBytesLocalDisk="1G"
           eternal="false"
           timeToLiveSeconds="600"
           timeToIdleSeconds="300"
           statistics="true"
           overflowToDisk="true"
           memoryStoreEvictionPolicy="LFU">
    </cache>

</ehcache>

这是我的 mybatis mapper 界面的示例。

import java.util.List;

public interface InstitutionMapper {

    @Cacheable(value = "mybatis")
    List<Institution> getAll();

    @Cacheable(value = "mybatis", key = "id")
    Institution getById(long id);

    @CacheEvict(value = "mybatis")
    void save(Institution institution);

    @CacheEvict(value = "mybatis", key = "id")
    void delete(long id);
}

因为我有一个共享缓存,所以我需要一种方法让我的键对域对象是唯一的。作为保存或删除的示例,我需要清除缓存,以便新值显示在 UI 上。但是我不想清除整个缓存。我不知道如何解决这个问题,以便在调用 delete 并驱逐缓存时,只有具有该 ID 的机构的 mybatis 缓存中的条目才会被清除。

密钥需要是域名+参数之类的东西。例如机构+ id。希望这是有道理的。

我看到了这篇文章,但它似乎是按类名+方法+参数进行的。

4

1 回答 1

3

为整个域模型设置一个区域有点奇怪(至少可以这么说)。我可以想象你可以在同一个缓存中收集具有相似语义的对象类型,但不是所有的对象类型。如果您有适当的划分,您在这里提出的大多数问题都会自行解决。

但为了便于解释,这里有一些想法。

getAll()需要一把钥匙。如果您不提供一个,那么基本上任何其他@Cacheable没有参数的方法都会与缓存中的相同键冲突。

@Cacheable(value = 'mybatis', key = "'institutions'")
List<Institution> getAll();

@CacheEvict不会(从getAll()方法中)清除缓存列表,因此您可能会遇到驱逐机构的情况,但它仍然会从缓存getAll()调用中显示出来。如果您想在多个级别缓存相同的内容,则最好在更新/删除某些内容时删除整个区域。如果每个实体类型都有一个区域,这当然不是问题。

你的save方法没有id。它到底应该驱逐什么?它如何知道必须通过 id 找到现有机构?

@CacheEvict(value = "mybatis", key = "#p0.id")
void save(Institution institution);

(但这并不能解决getAll()不一致问题)

getById不需要密钥,因为您拥有的唯一方法参数id。回到你原来的“问题”,如果你想在你的键前面加上一些东西,你需要全面地做(这样驱逐对同一个键起作用)。我不会在 SpEL 中这样做,因为忘记一个案例的机会太高了。

您可以KeyResolver根据方法的返回类型实现自定义并附加唯一前缀。

话虽如此,您的示例代码几乎不会出错,因此我建议您查看有关此主题的文档

于 2015-07-28T12:55:43.860 回答