Spring @Cacheable如何通过dao调用在服务级别工作

时间:2017-07-07 08:09:31

标签: java spring spring-boot

我有以下代码:

@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缓存不起作用,因为该方法仍然一直调用DB。另一方面,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注释。

听到MyCondition:

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
-------------------------------------------------------
=======================================================

1 个答案:

答案 0 :(得分:0)

正如StuPointerException所指出的那样(在他删除的答案中需要获得10000点声望)和评论中的M. Deinum,您需要同时实施equals()hashCode()你的MyCondition课程。

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

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

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

相关问题