I.
Through annotation, spring 3 above provides annotation for cache programming.
@Cacheable: used when querying. Note that Long type needs to be converted to Sting type, otherwise exceptions will be thrown.
@CachePut: used when updating. With this annotation, data will be queried from the DB.
@CacheEvict: used when deleting;
@Caching: please refer to the official website for the usage of specific annotation of combination usage
Note: Although the annotation method can make our code concise, it has limitations: key acquisition and invalid annotation when nesting.
// Use getUserByName to call getIdByName and getUser methods to implement queries, but use this method to call directly in the controller
//getUserByName method, the cache effect does not work. You must directly call getIdByName and getUser methods to work.
public User getUserByName(String name) { //Query the primary key by name and then query the entity by the primary key return getUser(Long.valueOf(getIdByName(name))); }
Two.
Non annotation implementation
1. Define a RedisCacheConfig class to generate RedisTemplate and manage CacheManager
@Configuration public class RedisCacheConfig extends CachingConfigurerSupport { /*Beans defining cache data key generation strategy *Package name + class name + method name + all parameters */ @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } //@Bean public CacheManager cacheManager( @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) { //RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); //cacheManager.setDefaultExpiration(60); / / set cache retention time (seconds) return cacheManager; } //1. When the project starts, this method is first registered as a bean and managed by spring. @Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); //Use Jackson 2jsonredisserializer to serialize and deserialize the value of redis Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class); System.out.println("==============obj:"+Object.class.getName()); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); serializer.setObjectMapper(mapper); template.setValueSerializer(serializer); //Use StringRedisSerializer to serialize and deserialize the key value of redis template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } }
2. Define a redisUtil class to access the cache value
@Component public class RedisCacheUtil { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private RedisTemplate<String, Object> redisTemplate; /** * Store string * @param key string Type key * @param value String value of type */ public void set(String key, String value) { stringRedisTemplate.opsForValue().set(key, value); } /** * Storage object * @param key String Type key * @param value Object value of type */ public void set(String key, Object value) { redisTemplate.opsForValue().set(key, value); } /** * Storage object * @param key String Type key * @param value Object value of type */ public void set(String key, Object value,Long timeOut) { redisTemplate.opsForValue().set(key, value,timeOut, TimeUnit.SECONDS); } /** * Get string data according to key * @param key * @return */ public String getValue(String key) { return stringRedisTemplate.opsForValue().get(key); } // public Object getValue(String key) { // return redisTemplate.opsForValue().get(key); // } /** * Get object according to key * @param key * @return */ public Object getValueOfObject(String key) { return redisTemplate.opsForValue().get(key); } /** * Delete cache information according to key * @param key */ public void delete(String key) { redisTemplate.delete(key); } /** * Query whether the key exists * @param key * @return */ @SuppressWarnings("unchecked") public boolean exists(String key) { return redisTemplate.hasKey(key); } }
3. Implementation class`/**
*
*
-
Based on Impl + prevent cache avalanche and cache penetration
*/
@Service(value = "userServiceImpl4")
public class UserServiceImpl4 implements UserService {@Autowired
UserMapper userMapper;@Autowired
RedisCacheUtil redisCacheUtil;@Value("${timeOut}")
private long timeOut;@Override
public User getUser(Long userId) {String key = "user" + userId; User user = (User) redisCacheUtil.getValueOfObject(key); String keySign = key + "_sign"; String valueSign = redisCacheUtil.getValue(keySign); if(user == null){//Prevent spatiotemporal results from being returned on the first query //Prevent cache penetration if(redisCacheUtil.exists(key)){ return null; } user = userMapper.selectByPrimaryKey(userId); redisCacheUtil.set(key,user); redisCacheUtil.set(keySign,"1",timeOut *(new Random().nextInt(10) + 1));
//redisCacheUtil.set(keySign, "1", 0L); / / expiration time cannot be set to 0, it must be a number greater than 0
return user;
}
if(valueSign != null){ return user; }else { //Set effective time of tag Long tt = timeOut * (new Random().nextInt(10) + 1); System.out.println("tt:"+tt); redisCacheUtil.set(keySign,"1",tt); //Asynchronous processing of cache update response and high concurrency will result in dirty reads ThreadPoolUtil.getExecutorService().execute(new Runnable(){ public void run() { // System.out.println("-----Perform asynchronous operation-----"); User user1 = userMapper.selectByPrimaryKey(userId); redisCacheUtil.set(key,user1); } });
// new Thread(){
//public void run() {/ / in case of high concurrency, dirty reading will occur.
//System.out.println("------ perform asynchronous operation -----");
// User user1 = userMapper.selectByPrimaryKey(userId);
// redisCacheUtil.set(key,user1);
// }
// }.start();
}
return user;
}
}`