1. Dependent Package InstallationPom.xml Join:<textarea style="display: none"><dependency> <groupId>org.springframework.data</groupId> <artifactid>spring-data-red is</artifactid> <version>1.6.0.RELEASE</version> </dependency> <dependency> < Groupid>redis.clients</groupid> <artifactId>jedis</artifactId> <version>2.7.3</ver Sion> </dependency></textarea>2. Spring project integrated into cache supportto enable cache support, we need to create a newCacheManagerBean. CacheManager interfaceThere are many implementations, and this article demonstrates the integration with Redis, which is naturally rediscachemanager. Redis is not an app's shared memory, it's just a memory server, like MYSQL, we need to connect the app to it and interact with some kind of "language," so we also need a connection factory and a redistemplate for the Spring and Redis conversations, These are the necessary configurations for the Redis cache and put them all in a custom cachingconfigurersupport:
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; @Configuration @EnableCaching public class Rediscacheconfig extends Cachingconfigurersupport {@Bean public Jedisconnectionfactory redisconnectionfactory () {jedisconnectionfactory redisconnectionfactory = new JedisConnec Tionfactory (); Redisconnectionfactory.sethostname ("192.168.1.166"); Redisconnectionfactory.setport (6379); Return rEdisconnectionfactory; } @Bean public redistemplate<string, string> redistemplate (Redisconnectionfactory CF) {Rediste mplate<string, string> redistemplate = new redistemplate<string, string> (); Redistemplate.setconnectionfactory (CF); return redistemplate; } @Bean Public CacheManager CacheManager (redistemplate redistemplate) {Rediscachemanager cachemanage R = new Rediscachemanager (redistemplate); Cachemanager.setdefaultexpiration (3000); return CacheManager; } }
of course, don't forget to inject these beans into Spring, otherwise the configuration will be invalid. Add the following in the Applicationcontext.xml<textarea style="display: none"><context:component-scan base-package= "Com.defonds.bdp.cache.redis"/></textarea>
3. Caching the execution results of some methods and caching data consistency guaranteesafter setting up the cache configuration, we can use @Cacheable annotations to cache the results of the method execution, such as retrieving the city's Provincecities method based on the province name and retrieving the city's Searchcity method based on City_code:CRUD (create creation, Retrieve read, update updates, delete delete) operations, in addition to the power of R, the other three can cause cache results and database inconsistencies. In order to ensure the consistency of the cached data, we need to update or clear the cache that may be affected when the CUD operation is performed.
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); } @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_c Ode) {this.cityMapper.deleteCity (City_code); return 1; }Business considerations, this example uses @CacheEvict to clear the cache. If your CUD can return to the city instance, you can also use the @CachePut to update the cache policy. I recommend that you use @CachePut where you do not use @CacheEvict, because the latter will all the relevant methods of the cache is cleared, such as any of the above three methods are called, the Provincecities method of all the cache will be cleared.
5. Custom cache Data Key generation policyfor a method that uses @Cacheable annotations, the key generation policy for each cache uses the parameter name + parameter value by default, such as the following methods:
<textarea style="display: none">@Cacheable ("users") public User Findbyusername (String username)</textarea>
The cache for this method will be stored in the cache with key Users~keys, and for username with the value "Zhao Defang", the key is "username-Zhao Defang". In general, there is no problem, the second case, if the method key value is equal and the parameter name is the same when the problem occurs, such as:
<textarea style="display: none">@Cacheable ("users") public Integer Getlogincountbyusername (String username)</textarea>
The cache for this method will also be stored in the cache of key Users~keys. For a cache with a value of "Zhao Defang" for username, key is also "username-Zhao Defang", overwriting the cache of another method.
The workaround is to use a custom cache policy, for the same business (the same business logic processing method, even the cluster/distributed system), the generated key always consistent, for different business is inconsistent:
<textarea style="display: none">@Bean public Keygenerator customkeygenerator () {Return to 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 (); } }; } </textarea>
This is important for sharing caches between clustered systems and distributed systems, and it really implements distributed caching.
The author suggests that the @Cacheable of the caching method is best to use the method name, avoid the @Cacheable values of the different methods consistent, and then with the above cache policy.
6. Validation of Cached 6.1 cachein order to determine whether each cache method actually has a cache, we have opened the SQL log output of MyBatis, and we have emptied the Redis database for testing to demonstrate clearly.
to verify the Provincecities method cache, Eclipse starts the Tomcat loading project and uses JMeter to invoke the/bdp/city/province/cities.json interface:
The Eclipse console output is as follows:
indicates that the request did not hit the cache, and the DB query was gone. JMeter request again, Eclipse console output:
Red Section The following is the log for this request, no log to access the DB, and a cache hit. To view Redis storage for this request:
It is also possible to verify that the cache for the Searchcity method with City_code 1492 is valid:
the red part of the figure is the cache storage of searchcity.
6.2 Validation of Cache consistencyto verify the cache configuration of the Insertcity method first, JMeter calls the/bdp/city/create.json interface:
then look at Redis storage:
It can be seen that the cache of the Provincecities method has been cleaned out and the cache of the Insertcity method works.
then verify the cache configuration of the Renamecity method, JMeter calls the/bdp/city/rename.json interface:
Then look at Redis storage:
The cache of the Searchcity method has also been cleaned up, and the caching of the Renamecity method has worked.
7. Precautions
- The Java object to be cached must implement the Serializable interface , because Spring will serialize the object first into Redis, such as the Com.defonds.bdp.city.bean.City class in this article, if not implemented Serializable will encounter a similar error:nested exception is Java.lang.IllegalArgumentException:DefaultSerializer requires a Serializable payload but received an object of type [com.defonds.bdp.city.bean.City]].
- The life cycle of the cache we can configure and then host Spring CacheManager, and do not attempt to manage the cache through the REDIS-CLI command line. For example, the Provincecities method Cache, a province of the query results will be stored in the form of key-value in Redis,key is our custom generated Key,value is the serialized object, this key will be placed in the key named Provinc Ecities~keys Key-value Storage, refer to the "Provincecities method in Redis cache condition". Provincecities~keys can be deleted by REDIS-CLI using the Del command, but the cache for each province is not cleared.
- CacheManager must set the cache expiration time, otherwise the cached object will never expire, so for the reasons above, avoid some wild data "forever save". In addition, setting the cache expiration time also helps maximize resource utilization, because the cache is always kept hot data.
- The cache is suitable for applications where there is less read and write, the cache hit rate is very low, the write operation is very frequent, and the scenario is not suitable for caching.
Example of Redis cache + Spring Integration (reproduced)