【问题标题】:@Cacheable Key on Shared Cache?共享缓存上的@Cacheable 键?
【发布时间】:2015-07-27 19:50:04
【问题描述】:

我有一个使用 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映射器界面示例。

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。希望这是有道理的。

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

【问题讨论】:

    标签: java spring caching ehcache spring-cache


    【解决方案1】:

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

    但为了解释起见,这里有一些想法。

    您的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 并根据方法的返回类型附加唯一前缀。

    话虽如此,您的示例代码几乎没有全部错误,所以我建议您查看documentation on this topic

    【讨论】:

    • 感谢您的详尽解释。听起来单个 Cache 不是一个好主意,也不是常见的做法。我认为我最好使用单独的缓存区域,或者在我的 MyBatis 映射器文件中使用 MyBatis ehcache 支持。
    猜你喜欢
    • 1970-01-01
    • 2011-01-04
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    • 2017-12-06
    相关资源
    最近更新 更多