共享缓存上的@Cacheable 键?
@Cacheable Key on Shared Cache?
我有一个 Spring 应用程序使用 MyBatis 进行持久化。我正在使用 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。希望这是有道理的。
我看到了这个 post 但它似乎是按 class 名称 + 方法 + 参数进行的。
为整个域模型设置一个区域有点奇怪(至少可以这么说)。我可以想象您可以在同一缓存中收集具有相似语义的对象类型,但不能收集 all 对象类型。如果你有适当的分界,你在这里问的大多数问题都会自行解决。
但为了解释方便,这里有一些想法。
您的 getAll()
需要一把钥匙。如果您不提供一个,那么基本上任何其他没有参数的 @Cacheable
方法都会与缓存中的相同键冲突。
@Cacheable(value = 'mybatis', key = "'institutions'")
List<Institution> getAll();
您的 @CacheEvict
不会清除缓存列表(通过 getAll()
方法),因此您可能会遇到这样的情况:您驱逐了一个机构,但它仍然显示在缓存 getAll()
打电话。如果你想在多个级别缓存相同的东西,你最好在 update/delete 某些东西时删除整个区域。如果每个实体类型都有一个区域,这当然不是什么问题。
您的 save
方法没有 ID。它究竟应该驱逐什么?它怎么知道它必须通过 id 找到一个现有的机构?
@CacheEvict(value = "mybatis", key = "#p0.id")
void save(Institution institution);
(虽然不能解决 getAll()
不一致的问题)
您的 getById
不需要密钥,因为那里唯一的方法参数 是 id。回到你原来的 "problem",如果你想给你的键加上一些前缀,你需要全面地做(这样驱逐就可以针对同一个键)。我不会在 SpEL 中这样做,因为忘记一个案例的机会太高了。
您可以实现自定义 KeyResolver
并根据方法的 return 类型附加一个唯一的前缀。
也就是说,您的示例代码几乎 全部 都是错误的,所以我建议您查看 documentation on this topic
我有一个 Spring 应用程序使用 MyBatis 进行持久化。我正在使用 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。希望这是有道理的。
我看到了这个 post 但它似乎是按 class 名称 + 方法 + 参数进行的。
为整个域模型设置一个区域有点奇怪(至少可以这么说)。我可以想象您可以在同一缓存中收集具有相似语义的对象类型,但不能收集 all 对象类型。如果你有适当的分界,你在这里问的大多数问题都会自行解决。
但为了解释方便,这里有一些想法。
您的 getAll()
需要一把钥匙。如果您不提供一个,那么基本上任何其他没有参数的 @Cacheable
方法都会与缓存中的相同键冲突。
@Cacheable(value = 'mybatis', key = "'institutions'")
List<Institution> getAll();
您的 @CacheEvict
不会清除缓存列表(通过 getAll()
方法),因此您可能会遇到这样的情况:您驱逐了一个机构,但它仍然显示在缓存 getAll()
打电话。如果你想在多个级别缓存相同的东西,你最好在 update/delete 某些东西时删除整个区域。如果每个实体类型都有一个区域,这当然不是什么问题。
您的 save
方法没有 ID。它究竟应该驱逐什么?它怎么知道它必须通过 id 找到一个现有的机构?
@CacheEvict(value = "mybatis", key = "#p0.id")
void save(Institution institution);
(虽然不能解决 getAll()
不一致的问题)
您的 getById
不需要密钥,因为那里唯一的方法参数 是 id。回到你原来的 "problem",如果你想给你的键加上一些前缀,你需要全面地做(这样驱逐就可以针对同一个键)。我不会在 SpEL 中这样做,因为忘记一个案例的机会太高了。
您可以实现自定义 KeyResolver
并根据方法的 return 类型附加一个唯一的前缀。
也就是说,您的示例代码几乎 全部 都是错误的,所以我建议您查看 documentation on this topic