1, Introduction
After spring boot 2. X, jedis in the bottom layer of spring boot starter data redis is replaced with lettuce. The project is the difference between jedis and lettuce
Jedis: direct connection is adopted. If there are multiple threads, it will lead to security risks. Of course, you can use jedis pool (BIO) connection pool to avoid thread insecurity.
lettuce: adopt netty , instances can be shared among multiple threads. There is no thread insecurity. It is more like Nio pattern
2, Integration
Step 1: create a springboot project
Slightly
Step 2: import redis dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
Step 3: configure redis profile
# Configure redis spring.redis.host=192.168.174.128 spring.redis.port=6379
Step 4: Test
We will use RedisTemplate to operate. opsForValue() is used to operate strings. We will explain the operation of various data types below.
@Autowired private RedisTemplate redisTemplate; @Test void contextLoads() { redisTemplate.opsForValue().set("name","studioustiger"); String name = (String)redisTemplate.opsForValue().get("name"); System.out.println(name); }
3, Use of Redis data types in RedisTemplate
When we used Jedis as like as two peas, we found that the command of Jedis operation Redis is basically the same as that of Redis, so we are very good at it.
However, in the RedisTemplate in springboot, we need to determine the data type of Redis you want to operate through the opsforxx () method, and then call the methods supported by the data type.
// The operation of String type, xxx(), is the various methods supported by String we talked about earlier redisTemplate.opsForValue().xxx() // The operation Set type, xxx() is the various methods supported by Set as we mentioned earlier redisTemplate.opsForSet().xxx() // Operate the Hash type. xxx() is the various methods supported by Hash we talked about earlier redisTemplate.opsForHash().xxx() // Operate the List type, xxx() is the various methods supported by the List we talked about earlier redisTemplate.opsForList().xxx() // Operating Zset type, xxx() is the various methods supported by Zset we talked about earlier redisTemplate.opsForZSet().xxx() // Operating Geo type, xxx() is the various methods supported by Geo we talked about earlier redisTemplate.opsForGeo().xxx() // To operate the HyperLogLog type, xxx() is the various methods supported by HyperLogLog we talked about earlier redisTemplate.opsForHyperLogLog().xxx()
4, Custom RestTemplate
1. Source code introduction
Let's first look at the source code to see why we can customize RestTemplate and how to customize it
Find spring.factories and open
RedisAutoConfiguration found
Enter RedisAutoConfiguration (see note)
@Configuration( proxyBeanMethods = false ) @ConditionalOnClass({RedisOperations.class}) // We can see what redis can configure in RedisProperties and the default values of some parameters @EnableConfigurationProperties({RedisProperties.class}) @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) public class RedisAutoConfiguration { public RedisAutoConfiguration() { } @Bean // ConditionalOnMissingBean: indicates that when there is a redisTemplate, the injected class will not take effect, which means that we can customize the redisTemplate to replace the default redisTemplate @ConditionalOnMissingBean( name = {"redisTemplate"} ) @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { // We see that the generic type of its RedisTemplate is < object, Object >, but we prefer < string, Object >, so we will pay attention to this later when rewriting RedisTemplate<Object, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean @ConditionalOnSingleCandidate(RedisConnectionFactory.class) // This is a redisTemplate that operates on strings. Because String is the most commonly used in redis, spring officially encapsulates a class. public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
Click RedisTemplate
We don't want to use jdk serialization. We think jkd serialization will cause garbled code in redis (even in English).
Through the above source code introduction, we know that if we want to store an object in redis, there are two ways. The first method: convert the string to be stored in redis into json, and then store it in redis. The second method is to serialize the entity classes used and store them in redis.
Let's customize the second method.
2. Write your own RedisTemplate
If you are impressed, we said earlier that in actual development, our entity classes need to be serialized. Function of serialization: a mechanism for managing object flow, which can easily save the state of java objects in memory and facilitate transmission. Therefore, the entity classes we use need to implement Serializable.
① Write a custom RedisTemplate
package com.tiger.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { // This is a custom serialization template that we can use directly in development @Bean @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { // For the convenience of our own development, we generally directly use < string, Object > RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); // Json serialization configuration 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); // Serialization of String StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // The key is serialized by String template.setKeySerializer(stringRedisSerializer); // The key of hash is also serialized by String template.setHashKeySerializer(stringRedisSerializer); // value is serialized by jackson template.setValueSerializer(jackson2JsonRedisSerializer); // The value serialization method of hash is jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
In "3", if we have redis data types, we need to determine the types and usage methods first. This method is really cumbersome, so we can customize a RedisUtil to simplify development
② RedisUtil tool class
package com.tiger.utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Redis Tool class*/ @Component public final class RedisUtil { @Autowired private RedisTemplate<String, Object> redisTemplate; // =============================common============================ /** * Specify cache expiration time * @param key key * @param time Time (seconds) */ public boolean expire(String key, long time) { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Get expiration time according to key * @param key Key cannot be null * @return Time (seconds) returns 0, which means it is permanently valid */ public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * Determine whether the key exists * @param key key * @return true Exists false does not exist */ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * Delete cache * @param key One or more values can be passed */ @SuppressWarnings("unchecked") public void del(String... key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key)); } } } // ============================String============================= /** * Normal cache fetch * @param key key * @return value */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * Normal cache put * @param key key * @param value value * @return true Success false failure */ public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Normal cache put and set time * @param key key * @param value value * @param time Time (seconds) time must be greater than 0. If time is less than or equal to 0, the infinite period will be set * @return true Success false failure */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Increasing * @param key key * @param delta How many to add (greater than 0) */ public long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("The increment factor must be greater than 0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * Diminishing * @param key key * @param delta How many to reduce (less than 0) */ public long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("Decrement factor must be greater than 0"); } return redisTemplate.opsForValue().increment(key, -delta); } // ================================Map================================= /** * HashGet * @param key Key cannot be null * @param item Item cannot be null */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * Get all key values corresponding to hashKey * @param key key * @return Corresponding multiple key values */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * @param key key * @param map Corresponding to multiple key values */ public boolean hmset(String key, Map<String, Object> map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * HashSet And set the time * @param key key * @param map Corresponding to multiple key values * @param time Time (seconds) * @return true Success false failure */ public boolean hmset(String key, Map<String, Object> map, long time) { try { redisTemplate.opsForHash().putAll(key, map); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Put data into a hash table. If it does not exist, it will be created * * @param key key * @param item term * @param value value * @return true Success false failure */ public boolean hset(String key, String item, Object value) { try { redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Put data into a hash table. If it does not exist, it will be created * * @param key key * @param item term * @param value value * @param time Time (seconds): Note: if the existing hash table has time, the original time will be replaced here * @return true Success false failure */ public boolean hset(String key, String item, Object value, long time) { try { redisTemplate.opsForHash().put(key, item, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Delete values from hash table * * @param key Key cannot be null * @param item Item can make multiple non null able */ public void hdel(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } /** * Judge whether there is a value of this item in the hash table * * @param key Key cannot be null * @param item Item cannot be null * @return true Exists false does not exist */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash If increment does not exist, it will create one and return the added value * * @param key key * @param item term * @param by How many to add (greater than 0) */ public double hincr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } /** * hash Diminishing * * @param key key * @param item term * @param by To reduce (less than 0) */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } // ============================set============================= /** * Get all the values in the Set according to the key * @param key key */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Query from a set according to value whether it exists * * @param key key * @param value value * @return true Exists false does not exist */ public boolean sHasKey(String key, Object value) { try { return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) { e.printStackTrace(); return false; } } /** * Put data into set cache * * @param key key * @param values Values can be multiple * @return Number of successful */ public long sSet(String key, Object... values) { try { return redisTemplate.opsForSet().add(key, values); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * Put set data into cache * * @param key key * @param time Time (seconds) * @param values Values can be multiple * @return Number of successful */ public long sSetAndTime(String key, long time, Object... values) { try { Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) expire(key, time); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * Gets the length of the set cache * * @param key key */ public long sGetSetSize(String key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * Remove with value * * @param key key * @param values Values can be multiple * @return Number of removed */ public long setRemove(String key, Object... values) { try { Long count = redisTemplate.opsForSet().remove(key, values); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } // ===============================list================================= /** * Get the contents of the list cache * * @param key key * @param start start * @param end End 0 to - 1 represent all values */ public List<Object> lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Gets the length of the list cache * * @param key key */ public long lGetListSize(String key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * Get the value in the list through the index * * @param key key * @param index When index index > = 0, 0 header, 1 second element, and so on; When index < 0, - 1, footer, - 2, the penultimate element, and so on */ public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Put list into cache * * @param key key * @param value value */ public boolean lSet(String key, Object value) { try { redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Put list into cache * @param key key * @param value value * @param time Time (seconds) */ public boolean lSet(String key, Object value, long time) { try { redisTemplate.opsForList().rightPush(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Put list into cache * * @param key key * @param value value * @return */ public boolean lSet(String key, List<Object> value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Put list into cache * * @param key key * @param value value * @param time Time (seconds) * @return */ public boolean lSet(String key, List<Object> value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Modify a piece of data in the list according to the index * * @param key key * @param index Indexes * @param value value * @return */ public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Remove N values as value * * @param key key * @param count How many are removed * @param value value * @return Number of removed */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); return remove; } catch (Exception e) { e.printStackTrace(); return 0; } } }
④ Testing
Note: the entity class we use implements the Serializable interface.
@Autowired @Qualifier("redisTemplate") private RedisTemplate redisTemplate; @Autowired private RedisUtil redisUtil; @Test void contextLoads() throws JsonProcessingException { User user = new User("tiger", 18, "male"); redisUtil.set("user",user); System.out.println(redisUtil.get("user").toString()); }
3. Considerations when serializing and deserializing
Serialization:
When the entity class needs to be serialized, the serialized entity class must implement the Serializable interface.
Deserialization:
If the following error occurs in your program
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of com.tiger.pojo.User (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.tiger.pojo.User (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
Then it means that there is no parameterless constructor in your entity class.
May you live up to your youth and return as a teenager