【存储中间件】JVM缓存EhCache(二):Cache注解的使用

发布于:2025-03-11 ⋅ 阅读:(90) ⋅ 点赞:(0)

在这里插入图片描述
个人主页:道友老李
欢迎加入社区:道友老李的学习社区

EhCache缓存

五、Cache注解使用

Cache注解是JSR规范中的,Spring支持这种注解。前面配置好关于CacheManager之后,就可以在Service层添加Cache注解,实现缓存使用,缓存更新,缓存清除。

5.1 @Cacheable

5.1.1 基本使用

这个是查询缓存的注解,可以加载方法上,也可以加在类上(不要添加在类上,这样很多细粒度配置就无法实现,比如@Transactional),可以在执行当前方法前,根据注解查看方法的返回内容是否已经被缓存,如果已经缓存,不需要执行业务代码,直接返回数据。如果没有命中缓存,正常执行业务代码,在执行完毕后,会将返回结果作为缓存,存储起来。

直接在Service层的方法上添加@Cacheable,注意,必须填写@Cacheable中的value或者cacheName属性

默认情况下,每次查询会基于Key(默认是方法的参数)去查看是否命中缓存

  • 如果命中缓存,直接返回
  • 如果未命中缓存,正常执行业务代码,基于方法返回结果做缓存
5.1.2 key的声明方式

key的声明方式有两种,一种是基于Spring的Expression Language去实现,另一种是基于编写类的方式动态的生成key

5.1.2.1 Spel表达式语言实现
@Override
@Cacheable(cacheNames = {"item"},key = "#id")    // 123
public String echo(String id,String... args) {
    System.out.println("查询数据库~");
    // itemMapper.findById(id);
    return id;
}

这种方式要基于Spel实现,但是Spel用的不过,单独为了这种操作熟悉Spel成本蛮高的,而且功能并不丰富,所以更推荐第二种方式,编写类的方式设置key的生成策略

5.1.2.2 KeyGenerator实现

这种方式需要在Spring容器中构建KeyGenerator实现类,基于注解配置进去即可

设置key的生成策略。

@Configuration
public class CacheKeyGenerator {

    @Bean(name = "itemKeyGenerator")
    public KeyGenerator itemKeyGenerator(){
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName() + params[0];
            }
        };
    }
}

设置bean name到keyGenerator中

@Override
@Cacheable(cacheNames = {"item"},keyGenerator = "itemKeyGenerator")   
public String echo(String id,String... args) {
    System.out.println("查询数据库~");
    // itemMapper.findById(id);
    return id;
}
5.1.3 缓存条件

在执行方法前后,判断当前数据是否需要缓存,所以一般基础参数的判断。

  • 条件为true代表缓存(condition)
  • 条件为false代表缓存(unless)

都可以基于Spel编写条件表达式

5.1.3.1 condition

在执行方法前,决定是否需要缓存

可以在condition中编写Spel,只要条件为true,既代表当前数据可以缓存

@Override
@Cacheable(cacheNames = {"item"},condition = "#id.equals(\"123\")")
public String echo(String id) {
    System.out.println("查询数据库~");
    // itemMapper.findById(id);
    return id;
}
5.1.3.2 unless

执行方法之后,决定是否需要缓存

unless也可以编写Spel,条件为false时,代表数据可以缓存,如果为true,代表数据不需要缓存

@Override
@Cacheable(cacheNames = {"item"},unless = "#result.equals(\"123\")")
public String echo(String id) {
    System.out.println("查询数据库~");
    // itemMapper.findById(id);
    return id;
}

更多的其实还是在执行查询前,来判断数据是否需要缓存。如果真的需要做,也是避免诡异的操作。

比如Service在出现异常结果时,返回-1,那么这种-1,就不需要缓存。

5.1.3.3 condition&unless的优先级

condition和unless都是代表是都需要缓存数据。

如果同时设置condition和unless。

  • condition,unless
  • true,false:都代表缓存,那就缓存喽。
  • true,true:unless代表不缓存,那就不缓存
  • false,false:condition代表不缓存数据,那就不缓存
  • false,true:都不让缓存, 那就不缓存

condition和unless没有优先级之分,他的优先级在于,不缓存的优先级高于缓存。

5.2.4 sync

缓存击穿问题。

当多个线程并发访问一个Service方法时,发现当前方法没有缓存数据,此时会让一个线程去执行业务代码查询数据,扔到缓存中,后面线程再查询缓存

可以设置sync属性为true,代表当执行Service方法时,发现缓存没数据,那么就需要去竞争锁资源去执行业务代码,后续线程等待前置线程执行完,再去直接查询缓存即可

@Override
@Cacheable(cacheNames = {"item"},sync = true)
public String echo(String id) {
    System.out.println("查询数据库~");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return id;
}

5.2 @CachePut

@CachePut注解巨简单,是在写数据之后,更新缓存的数据

在增删改的操作上追加@CachePut注解,会根据key去重置指定的缓存。

细节点就在于对标上查询方法的key

@Override
@CachePut(cacheNames = "item",key = "#item.id")
public String write(Item item) {
    // 写id为123的数据
    System.out.println("123被改成456");
    return "456";
}

@Cacheable其他的属性,和@Cacheable一模一样~~~

5.3 @CacheEvict

@CacheEvict是用来清楚缓存的,可以根据注解里的cacheNames和key来清除指定缓存,也可以清除整个cacheNames中的全部缓存

清除指定缓存

@Override
@CacheEvict(value = "item")
public void clear(String id) {
    System.out.println("清除缓存成功!");
}

清除全部缓存

@Override
@CacheEvict(value = "item",allEntries = true)
public void clearAll() {
    System.out.println("清除item中的全部缓存~!");
}

如果执行清除缓存过程中,业务代码出现异常,会导致无法正常清除缓存,可以设置一个属性来保证在方法业务执行之前,就将缓存正常清除beforeInvocation设置为true

@Override
@CacheEvict(value = "item",allEntries = true,beforeInvocation = true)
public void clearAll() {
    int i = 1 / 0;
    System.out.println("方法执行前,清除item中的全部缓存~!");
}

5.4 @Caching

没啥说的,一个组合数据,可以基于Caching实现@Cacheable,@CachePut以及@CacheEvict三个注解


网站公告

今日签到

点亮在社区的每一天
去签到