Redis Cache + Spring Integration Example

http://blog.csdn.net/defonds/article/details/48716161

"Integrating spring 4 (including mvc, context, orm) + mybatis 3 example" briefly introduces the latest versions of Spring MVC, IOC, MyBatis ORM integration and declarative transaction processing. Now we need to integrate the cache. We choose Redis for the cache. This article will introduce the integration of Redis cache + Spring based on the example in this article. For the construction of the Redis server, please refer to the blog "Compile and Install Redis in the Redhat5.8 Environment and Register it as a System Service".
1. Add dependency package installation
pom.xml:
[html] view plain copy print?
<!-- redis cache related.....start --> 
<dependency> 
    <groupId>org.springframework.data</groupId> 
    < artifactId>spring-data-redis</artifactId> 
    <version>1.6.0.RELEASE</version> 
</dependency> 
<dependency> 
    <groupId>redis.clients</groupId> 
    <artifactId>jedis< 
    <version>2.7.3</version> 
</dependency> 
<!-- redis cache related.....end --> 

2. Spring project integrates cache support
To enable cache support, we need to create a new CacheManager beans. There are many implementations of the CacheManager interface. This article demonstrates the integration with Redis. Naturally, RedisCacheManager is used. Redis is not shared memory for the application, it's just an in-memory server, just like MySql, we need to connect the application to it and use some "language" to interact, so we also need a connection factory and a Spring and Redis dialog to Use RedisTemplate, these are all necessary configurations for Redis cache, put them all in custom CachingConfigurerSupport:
[java] view plain copy print?
/**
* File Name: RedisCacheConfig.java
*
* Copyright Defonds Corporation 2015 
* All Rights Reserved
*
*/ 
package com.defonds.bdp.cache.redis; 
 
import org.springframework.cache.CacheManager; 
import org.springframework.cache.annotation.CachingConfigurerSupport; 
import org.springframework.cache.annotation.EnableCaching; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.data.redis.cache.RedisCacheManager; 
import org.springframework.data.redis.connection.RedisConnectionFactory; 
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 
import org.springframework.data.redis.core.RedisTemplate; 
 
/**

* Project Name:bdp 
* Type Name:RedisCacheConfig 
* Type Description:
*  Author:Defonds
* Create Date:2015-09-21

* @version

*/ 
@Configuration 
@EnableCaching 
public class RedisCacheConfig extends CachingConfigurerSupport { 
 
    @Bean 
    public JedisConnectionFactory redisConnectionFactory() { 
        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); 
 
        // Defaults 
        redisConnectionFactory.setHostName("192.168.1.166"); 
        redisConnectionFactory.setPort(6379); 
        return redisConnectionFactory; 
    } 
 
    @Bean 
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) { 
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>(); 
        redisTemplate.setConnectionFactory(cf); 
        return redisTemplate; 
    } 
 
    @Bean 
    public CacheManager cacheManager(RedisTemplate redisTemplate) { 
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); 
 
        // Number of seconds before expiration. Defaults to unlimited (0) 
        cacheManager.setDefaultExpiration(3000); // Sets the default expire time (in seconds) 
        return cacheManager; 
    } 
     


Of ​​course, don't forget to inject these beans into Spring, otherwise the configuration will be invalid. Add the following to applicationContext.xml:
[html] view plain copy print?
<context:component-scan base-package="com.defonds.bdp.cache.redis" /> 

3. Cache the execution results of certain methods After
setting the cache configuration, we can use the @Cacheable annotation to cache the results of method execution For example, the provinceCities method for retrieving cities based on province name and the searchCity method for retrieving cities based on city_code:
[java] view plain copy print?
// R 
@Cacheable("provinceCities") 
public List<City> provinceCities(String province) { 
    logger .debug("province=" + province); 
    return this.cityMapper.provinceCities(province); 

 
// R 
@Cacheable("searchCity") 
public City searchCity(String city_code){ 
    logger.debug("city_code=" + city_code ); 
    return this.cityMapper.searchCity(city_code);    


4. Cache data consistency guarantee
In the CRUD (Create creation, Retrieve read, Update update, Delete delete) operation, except that R is idempotent, the other three may cause inconsistency between the cached result and the database. In order to ensure the consistency of cached data, we need to update or clear the cache that may be affected when performing CUD operations.
[java] view plain copy print?
// C 
@CacheEvict(value = { "provinceCities"}, allEntries = true) 
public void insertCity(String city_code, String city_jb,  
        String province_code, String city_name, 
        String city, String province) { 
    City cityBean = new City(); 
    cityBean.setCityCode(city_code); 
    cityBean.setCityJb(city_jb); 
    cityBean.setProvinceCode(province_code); 
    cityBean.setCityName(city_name); 
    cityBean.setCity(city); 
    cityBean.setProvince(province); 
    this.cityMapper.insertCity(cityBean); 

// U 
@CacheEvict(value = { "provinceCities", "searchCity" }, allEntries = true) 
public int renameCity(String city_code, String city_name) { 
    City city = new City(); 
    city.setCityCode(city_code); 
    city.setCityName(city_name); 
    this.cityMapper.renameCity(city); 
    return 1; 

 
// D 
@CacheEvict(value = { "provinceCities", "searchCity" }, allEntries = true) 
public int deleteCity(String city_code) { 
    this.cityMapper.deleteCity(city_code); 
    return 1; 


For business considerations, this example uses @CacheEvict to clear the cache. If your CUD can return a City instance, you can also use @CachePut to update the cache strategy. The author recommends not to use @CacheEvict where @CachePut can be used, because the latter will clear the cache of all related methods. For example, if any of the above three methods are called, all caches of the provinceCities method will be cleared.
5. Customize the key generation strategy for cached data
For methods annotated with @Cacheable, the default key generation strategy for each cache uses the parameter name + parameter value, such as the following method:
[java] view plain copy print?
@Cacheable(" users") 
public User findByUsername(String username) 

The cache of this method will be stored in the cache whose key is users~keys. For the cache whose username is "Zhao Defang", the key is "username-Zhao Defang". In general, there is no problem. In the second case, there is a problem when the method keys are equal and the parameter names are the same, such as:
[java] view plain copy print?
@Cacheable("users") 
public Integer getLoginCountByUsername(String username) 

The cache of this method will also be stored in the cache with the key of users~keys. For caches whose username is "Zhao Defang", the key is also "username-Zhao Defang"
The solution is to use a custom caching strategy. For the same business (the same business logic processing method, even if it is a cluster/distributed system), the generated keys are always the same, but not for different businesses:
[java] view plain copy print?
@ Bean 
public KeyGenerator customKeyGenerator() { 
    return new KeyGenerator() { 
        @Override 
        public Object generate(Object o, Method method, Object... objects) { 
            StringBuilder sb = new StringBuilder(); 
            sb.append(o.getClass(). getName()); 
            sb.append(method.getName()); 
            for (Object obj : objects) { 
                sb.append(obj.toString()); 
            } 
            return sb.toString(); 
        } 
    }; 


Therefore, for the above two methods, for the cache whose username value is "Zhao Defang", although they are still stored in the cache whose key is users~keys, because the keys are "class name-findByUsername-username-Zhao Defang" and "class name" respectively -getLoginCountByUsername-username-Zhao Defang", so there will be no problem.
This is very important for sharing caches between cluster systems and distributed systems, and truly realizes distributed caching.
The author recommends that the @Cacheable of the cache method should use the method name to avoid the same @Cacheable value of different methods, and then match the above caching strategy.
6. Cache Validation
6.1 Cache Validation
In order to determine whether each cache method is cached or not, we opened the SQL log output of MyBatis, and for the sake of demonstration, we also emptied the Redis database for testing.
First, verify the provisionCities method cache. After Eclipse starts tomcat and loads the project, use JMeter to call the /bdp/city/province/cities.json interface:
use JMeter to call the /bdp/city/province/cities.json interface.png The
Eclipse console output is as follows : The
Eclipse console output is as follows.png
indicates that the request did not hit the cache this time, and the db query was used. JMeter requests again, Eclipse console output:
Eclipse console
output The following is the log of this request, there is no access to the db log, and the cache hits. Check the Redis storage for this request:
Checking the Redis storage of this
request.png can also verify whether the cache of the searchCity method with a city_code of 1492 is valid:
it can also verify whether the cache of the searchCity method with a city_code of 1492 is valid
. The red part in the figure is the cache storage of searchCity.
6.2 Cache consistency verification Let's
first verify the cache configuration of the insertCity method. JMeter calls the /bdp/city/create.json interface:
JMeter calls the /bdp/city/create.json interface
. It can be seen that the cache of the provinceCities method has been cleaned up, and the cache of the insertCity method has worked. Then verify the cache configuration of the renameCity method, JMeter calls the /bdp/city/rename.json interface: JMeter calls the /bdp/city/rename.json interface.png and then look at Redis storage: then look at Redis storage.png searchCity method cache has also been cleaned up and the cache of the renameCity method worked. 7. Precautions








The Java object to be cached must implement the Serializable interface, because Spring will serialize the object first and then store it in Redis, such as the com.defonds.bdp.city.bean.City class in this article, if you do not implement Serializable, you will encounter similar This kind of error: nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.defonds.bdp.city.bean.City]].
We can configure the cache life cycle, and then host the Spring CacheManager, don't try to manage the cache through the redis-cli command line. For example, in the cache of the provinceCities method, the query result of a certain province will be stored in Redis in the form of key-value. The key is the key we just customized, and the value is the serialized object. This key will be placed in the key name. For the provinceCities~keys key-value storage, refer to the following figure "provinceCities method caching in Redis". ProvinceCities~keys can be deleted using the del command from redis-cli, but the cache of each province will not be cleared.
CacheManager must set the cache expiration time, otherwise the cache object will never expire. The reason for this is as above, to avoid some wild data "permanently saved". In addition, setting the cache expiration time will also help maximize resource utilization, because the cache will always retain hot data.
Cache is suitable for occasions with more reads and less writes. Caches are not suitable for scenarios such as low cache hit rate and frequent write operations during query.
The storage of provinceCities method in Redis.png Postscript
The complete development project example under Eclipse has been uploaded to CSDN resources. Interested friends can download it for reference: http://download.csdn.net/detail/defonds/9137505. References Caching Data with Spring 35. Cache Abstraction Part VII. Integration Caching Data in Spring Using Redis Caching with Spring Data Redis spring-redis-caching-example







Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326935387&siteId=291194637
Recommended