SpringCache的key拼接
https://www.nhooo.com/note/qah5c5.html
@Cacheable(value = "page_user",key ="T(String).valueOf(#page).concat('-').concat(#pageSize)",unless = "#result=null")//由于page是int型,concat要求变量必须为String,所以强转一下 @Override public List<SysUserEntity> page(int page, int pageSize) { return userMapper.page(page,pageSize); }
https://blog.csdn.net/joy_pan/article/details/99298980
老外很厉害,茴香豆的写法有很多:
https://askcodes.net/coding/@cacheable-key-on-multiple-method-arguments
@Cacheable key on multiple method arguments
Problem :
From the spring documentation :
@Cacheable(value="bookCache", key="isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
How can I specify @Cachable
to use isbn
and checkWarehouse
as key?
Tags : java,spring,ehcache
Answer 1:
Update: Current Spring cache implementation uses all method parameters as the cache key if not specified otherwise. If you want to use selected keys, refer to Arjan's answer which uses SpEL list {#isbn, #includeUsed}
which is the simplest way to create unique keys.
From Spring Documentation
The default key generation strategy changed with the release of Spring 4.0. Earlier versions of Spring used a key generation strategy that, for multiple key parameters, only considered the hashCode() of parameters and not equals(); this could cause unexpected key collisions (see SPR-10237 for background). The new 'SimpleKeyGenerator' uses a compound key for such scenarios.
Before Spring 4.0
I suggest you to concat the values of the parameters in Spel expression with something like key="#checkWarehouse.toString() + #isbn.toString()")
, I believe this should work as org.springframework.cache.interceptor.ExpressionEvaluator returns Object, which is later used as the key so you don't have to provide an int
in your SPEL expression.
As for the hash code with a high collision probability - you can't use it as the key.
Someone in this thread has suggested to use T(java.util.Objects).hash(#p0,#p1, #p2)
but it WILL NOT WORK and this approach is easy to break, for example I've used the data from SPR-9377 :
System.out.println( Objects.hash("someisbn", new Integer(109), new Integer(434)));
System.out.println( Objects.hash("someisbn", new Integer(110), new Integer(403)));
Both lines print -636517714 on my environment.
P.S. Actually in the reference documentation we have
@Cacheable(value="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
I think that this example is WRONG and misleading and should be removed from the documentation, as the keys should be unique.
P.P.S. also see https://jira.springsource.org/browse/SPR-9036 for some interesting ideas regarding the default key generation.
I'd like to add for the sake of correctness and as an entertaining mathematical/computer science fact that unlike built-in hash, using a secure cryptographic hash function like MD5 or SHA256, due to the properties of such function IS absolutely possible for this task, but to compute it every time may be too expensive, checkout for example Dan Boneh cryptography course to learn more.
Answer 2:
After some limited testing with Spring 3.2, it seems one can use a SpEL list: {..., ..., ...}
. This can also include null
values. Spring passes the list as the key to the actual cache implementation. When using Ehcache, such will at some point invoke List#hashCode(), which takes all its items into account. (I am not sure if Ehcache only relies on the hash code.)
I use this for a shared cache, in which I include the method name in the key as well, which the Spring default key generator does not include. This way I can easily wipe the (single) cache, without (too much...) risking matching keys for different methods. Like:
@Cacheable(value="bookCache",
key="{ #root.methodName, #isbn?.id, #checkWarehouse }")
public Book findBook(ISBN isbn, boolean checkWarehouse)
...
@Cacheable(value="bookCache",
key="{ #root.methodName, #asin, #checkWarehouse }")
public Book findBookByAmazonId(String asin, boolean checkWarehouse)
...
Of course, if many methods need this and you're always using all parameters for your key, then one can also define a custom key generator that includes the class and method name:
<cache:annotation-driven mode="..." key-generator="cacheKeyGenerator" />
<bean id="cacheKeyGenerator" class="net.example.cache.CacheKeyGenerator" />
...with:
public class CacheKeyGenerator
implements org.springframework.cache.interceptor.KeyGenerator {
@Override
public Object generate(final Object target, final Method method,
final Object... params) {
final List<Object> key = new ArrayList<>();
key.add(method.getDeclaringClass().getName());
key.add(method.getName());
for (final Object o : params) {
key.add(o);
}
return key;
}
}
Answer 3:
You can use a Spring-EL expression, for eg on JDK 1.7:
@Cacheable(value="bookCache", key="T(java.util.Objects).hash(#p0,#p1, #p2)")
Answer 4:
You can use Spring SimpleKey class
@Cacheable(value = "bookCache", key = "new org.springframework.cache.interceptor.SimpleKey(#isbn, #checkWarehouse)")
Answer 5:
This will work
@Cacheable(value="bookCache", key="#checkwarehouse.toString().append(#isbn.toString())")
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现