【问题标题】:How can spring @Cacheable work in service level with a dao callspring @Cacheable 如何通过 dao 调用在服务级别工作
【发布时间】:2017-07-07 08:09:30
【问题描述】:

我有以下代码:

@Service
public class MyServiceImpl implements MyService {
    @Autowired
    private MyDao myDao;

    @Cacheable("callDao")
    @Override
    public MyResultModel callDao(MyCondition condition) {
        System.out.println("call without cache");
        return myDao.call(condition);
    }

    @Cacheable("cacheTest")
    @Override
    public MyResultModel cacheTest(MyCondition condition) {
        System.out.println("call without cache");
        return new MyResultModel(someProperties);
    }
}

但是,callDao 缓存不起作用,因为该方法仍然一直调用数据库。另一方面,cacheTest 确实可以正常工作。我的callDao 方法有什么问题?

这是我的配置:

@Bean
public CacheManager cacheManager(RedisCacheManagerConfiguration configuration,
        @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
    RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
    cacheManager.setDefaultExpiration(configuration.getDefaultExpiration());
    cacheManager.setUsePrefix(configuration.isUsePrefix());
    cacheManager.setLoadRemoteCachesOnStartup(configuration.isLoadRemoteCachesOnStartup());
    return cacheManager;
}

@Bean
public RedisTemplate<String, String> stringRedisTemplate(
        @Qualifier("stringRedisSerializer") RedisSerializer<String> keySerializer,
        @Qualifier("stringRedisSerializer") RedisSerializer<String> valueSerializer,
        @Qualifier("stringRedisSerializer") RedisSerializer<String> hashKeySerializer,
        @Qualifier("stringRedisSerializer") RedisSerializer<String> hashValueSerializer,
        JedisConnectionFactory connectionFactory) {
    StringRedisTemplate template = new StringRedisTemplate();
    template.setKeySerializer(keySerializer);
    template.setValueSerializer(valueSerializer);
    template.setHashKeySerializer(hashKeySerializer);
    template.setHashValueSerializer(hashValueSerializer);
    template.setConnectionFactory(connectionFactory);
    template.afterPropertiesSet();

    return template;
}

@Bean(name = "stringRedisSerializer")
public StringRedisSerializer stringRedisSerializer() {
    return new StringRedisSerializer();
}

我只配置了CacheManagerRedisTemplate。我还添加了@EnableCaching 注释。

听到是我的条件:

public class MyCondition implements Serializable {

    /** 
     * @since JDK 1.8
     */  
    private static final long serialVersionUID = 6262123870251938833L;

    private String guid;
    private Boolean isDelete;

    public String getGuid() {
        return guid;
    }

    public void setGuid(String guid) {
        this.guid = guid;
    }

    public Boolean getIsDelete() {
        return isDelete;
    }

    public void setIsDelete(Boolean isDelete) {
        this.isDelete = isDelete;
    }
}

听听我如何称呼这些方法

@EnableCaching
@EnableAutoConfiguration
@ComponentScan({ "com.mypackage" })
@SpringBootApplication
public class Application extends ContextIdApplicationContextInitializer {
    public static ConfigurableApplicationContext ctx;

    public static void main(String[] args) throws Exception {
        ctx = SpringApplication.run(Application.class, args);

        MyService myService = ctx.getBean(MyService.class);

        for (int i = 0; i < 10; i++) {
            MyCondition condition = new ConditionForRideCard();
            condition.setGuid("adsgsfdhgsfgfdghhsdfgfadf");
            myService.callDao(condition);
            System.out.println("-------------------------------------------------------");
            myService.cacheTest(condition);
            System.out.println("=======================================================");
            Thread.sleep(1000);
        }
    }
}

我得到这样的结果:

call without cache
-------------------------------------------------------
call without cache
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================
call without cache
-------------------------------------------------------
=======================================================

【问题讨论】:

  • PS:我用redis配置我的缓存。
  • 可能与您的缓存配置有关。做张贴
  • 感谢您的帮助,我的配置已发布。 @黑暗
  • 你能显示MyCondition的代码吗?另外,如何调用callDao 方法?您是从不同的类/服务还是在同一服务中调用它?
  • MyCondition 类中实现 hashCodeequals

标签: java spring spring-boot


【解决方案1】:

正如StuPointerException 指出的(在他删除的答案中,需要10000 声望才能看到)和cmets 中的M. Deinum,您需要在MyCondition 类中同时实现equals()hashCode()

Spring 的缓存抽象通过缓存基于参数的方法调用的结果来工作。在这种情况下,您只有一个参数 (MyCondition)。但是,生成的密钥将使用参数的hashCode() 实现。

在您的情况下,您没有实现equals()hashCode(),因此每次创建新的MyCondition 对象时,它都会有不同的哈希码,因此,Spring 不会知道它有其结果已缓存。

这并不能解释为什么cacheTest() 方法确实有效。但我想这是因为我们现在没有看到代码(要么你使用了不同的条件,要么发生了其他事情)。

【讨论】:

  • 非常感谢。我终于解决了我的问题。原因是,我在 mybatis inteceptor 中修改了 mycondition。然后redis的key就变了。所以第二次调用不能命中缓存。
猜你喜欢
  • 1970-01-01
  • 2014-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-31
  • 1970-01-01
  • 2018-12-24
  • 2021-05-24
相关资源
最近更新 更多