“This is the 16th day of my participation in the August More Text Challenge.
1, Lettuce,
Summary of Lettuce
After Spring Boot 2.x, the Redis client driver changed from Jedis to Lettuce
There are a lot of interesting features in the database, for example:
- Netty based, support event model
- Supports synchronous, asynchronous, and responsive modes
- Easy access to Redis Sentinel
- Full support for Redis Cluster
- The SSL connection
- Streaming API
- CDI and Spring integration
- Compatible with Java 8 and 9
Lettuce official document: github.com/lettuce-io/…
Lettuce and Jedis differ:
If you want to use Jedis in a multi-threaded environment, you need to use a connection pool. Each thread takes its own Jedis instance. As the number of connections increases, the cost of physical connections becomes high.
Lettuce is based on Netty, which is a multi-threaded, event-driven I/O framework, so Lettuce can help us take full advantage of asynchrony. The asynchronous approach allows us to make better use of system resources without wasting threads waiting for network or disk I/O.
2, automatic assembly of Redis principle
Spring Boot has two ways of using the Redis integration: manually manipulating the RedisTemplate or using redis cache annotations. Here we choose the RedisTemplate method.
Spring packages the RedisTemplate to operate Redis, and it supports all of the Redis native apis. The RedisTemplate defines manipulation methods for five data structures.
The following RedisAutoConfiguration source code defines two implementations of RedisTemplate, RedisTemplate and StringRedisTemplate.
And SpringBoot automatically assembs the beans we need to integrate Redis, so we just need to get them directly from the Spring container.
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
/ / import the other two configuration class LettuceConnectionConfiguration, JedisConnectionConfiguration,
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate") // If the container does not inject the redisTemplate bean, the current code block takes effect. If the container does have the redisTemplate bean, the annotated code block is not executed
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
returntemplate; }}Copy the code
In source above you can see two other configuration class imported the LettuceConnectionConfiguration, JedisConnectionConfiguration:
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
Copy the code
The two classes are used to configure the underlying Redis connection component, RedisConnectionFactory. One is based on the oracle Redis client implementation, and the other is based on the Jedis Redis client implementation. Because packet spring – the boot – starter – data – redis itself dependent on lettuce, so LettuceConnectionConfiguration will take effect, JedisConnectionConfiguration don’t take effect.
3. Spring Boot integrates Redis
1. Create a SpringBoot project
Redis dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Copy the code
2. Configure the connection
spring.redis.host=127.0.0.1
spring.redis.port=6379
Copy the code
3. Simple tests
@Autowired
private RedisTemplate redisTemplate; // Use the default RedisTemplate
@Test
void contextLoads(a) {
// redisTemplate
// opsForValue() operation String similar to String
OpsForList () operates like List
// opsForSet()
// opsForHash()
// opsForZSet()
// opsForGeo()
// opsForHyperLogLog()
In addition to basic operations, common methods can directly redisTemplate operations such as transaction CRUD
// Get the Redis connection object
// RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
// connection.flushDb();
// connection.flushAll();
redisTemplate.opsForValue().set("key1"."value1");
System.out.println(redisTemplate.opsForValue().get("key1"));
}
Copy the code
4. Customize RedisTemplate
Why customize the RedisTemplate?
1. SpringBoot automatically generates a RedisTemplate and a StringRedisTemplate in the container. However, the RedisTemplate’s generic type is <Object,Object>; We need a RedisTemplate of the form <String,Object>.
2. Custom serialization
In JAVA, everything is an object, and converting an object’s state information into storage or transport requires serialization.
Write an entity class without serializing it:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
}
Copy the code
Testing:
@Autowired
private RedisTemplate redisTemplate;
@Test
void test(a){
User user = new User("A thousand miles to go.".3);
// Set the user object to redis
redisTemplate.opsForValue().set("user",user);
System.out.println(redisTemplate.opsForValue().get("user"));
}
Copy the code
Run: appear org. Springframework. Data. Redis. Serializer. SerializationException: always serialize; Exception because the object was not serialized.
Serialize the User entity class
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String name;
private int age;
}
Copy the code
Run it again:
Successfully obtained the User object!
Spring provides serialization methods:
Check RedisTemplate source, RedisTemplate default serialization is JdkSerializationRedisSerializer, Using JdkSerializationRedisSerializer serialization way out value will appear garbled.
Write a custom RedisTemplate
package com.cheng.springbootredis.config;
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;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// Customize String Object
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// Json serialization configuration
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
/ / ObjectMapper translation
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();
// Key uses String serialization
template.setKeySerializer(stringRedisSerializer);
// The hash key also uses String serialization
template.setHashKeySerializer(stringRedisSerializer);
// Value serialization uses Jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// The hash value serialization method uses Jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
returntemplate; }}Copy the code
To facilitate the use of Redis, write redis utility classes
package com.cheng.springbootredis.utils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public final class RedisUtils {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public Set<String> keys(String keys){
try {
return redisTemplate.keys(keys);
}catch (Exception e){
e.printStackTrace();
return null; }}/** * specifies the cache expiration time *@paramThe key key *@paramTime Time (seconds) *@return* /
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 by key *@paramThe key key cannot be NULL *@returnTime (s) returns 0 for permanently valid */
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/** * Check whether the key exists *@paramThe key key *@returnTrue Exists false Does not exist */
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false; }}/** * delete cache *@paramKey can pass one value or more */
@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)); }}}/** * Common cache fetch *@paramThe key key *@returnValue * /
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/** * Normal cache into *@paramThe key key *@paramThe value value *@returnTrue Successful false failed */
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, no put, return *@paramThe key key *@paramThe value value *@returnTrue Successful false failed */
public boolean setnx(String key, Object value) {
try {
redisTemplate.opsForValue().setIfAbsent(key,value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false; }}/** * Normal cache is placed and set time *@paramThe key key *@paramThe value value *@paramTime Time (s) Time must be greater than 0. If time is less than or equal to 0, the value is set indefinitely *@returnTrue Successful false failed */
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; }}/** * Normal cache to place and set the time, if there is no place, return *@paramThe key key *@paramThe value value *@paramTime Time (s) Time must be greater than 0. If time is less than or equal to 0, the value is set indefinitely *@returnTrue Successful false failed */
public boolean setnx(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().setIfAbsent(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false; }}/** * increment *@paramThe key key *@paramDelta is incremented by a number (greater than 0) *@return* /
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("The increasing factor must be greater than zero.");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/** * decrements *@paramThe key key *@paramDelta is reduced by a number (less than 0) *@return* /
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("The decrement factor must be greater than zero.");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
/**
* HashGet
* @paramThe key key cannot be NULL *@paramItem items cannot be null *@returnValue * /
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/** * get all keys * corresponding to the hashKey@paramThe key key *@returnCorresponding multiple key values */
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
* @paramThe key key *@paramMap corresponds to multiple key values *@returnTrue Successful false failed */
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 *@paramThe key key *@paramMap corresponds to multiple key values *@paramTime Time (seconds) *@returnTrue Successful false failed */
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; }}/** * puts data into a hash table, or creates * if none exists@paramThe key key *@paramItem item *@paramThe value value *@returnTrue Successful false failed */
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; }}/** * puts data into a hash table, or creates * if none exists@paramThe key key *@paramItem item *@paramThe value value *@paramTime Time (s) Note: If the existing hash table has time, the original time * will be replaced@returnTrue Successful false failed */
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 the value * from the hash table@paramThe key key cannot be NULL *@paramItem items can be more than null */
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/** * Determines whether the value of the item * exists in the hash table@paramThe key key cannot be NULL *@paramItem items cannot be null *@returnTrue Exists false Does not exist */
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/** * hash increments that do not exist create one and return the new value *@paramThe key key *@paramItem item *@paramBy is going to be increased by how much (greater than 0) star@return* /
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/** * hash decrement *@paramThe key key *@paramItem item *@paramI'm going to subtract by (less than 0) star@return* /
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
/** * Get all values in the Set based on key *@paramThe key key *@return* /
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null; }}/** * select * from a set based on value@paramThe key key *@paramThe value value *@returnTrue 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 the data into the set cache *@paramThe key key *@paramValues can be multiple *@returnNumber of successes */
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 *@paramThe key key *@paramTime Time (seconds) *@paramValues can be multiple *@returnNumber of successes */
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; }}/** * Get the length of the set cache *@paramThe key key *@return* /
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0; }}/** * removes * from value@paramThe key key *@paramValues can be multiple *@returnNumber of removals */
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=================================
/** * retrieve the contents of the list cache *@paramThe key key *@paramStart to *@paramEnd End 0 to -1 represent all values *@return* /
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; }}/** * Get the length of the list cache *@paramThe key key *@return* /
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0; }}/** * Get the value * from the list by index@paramThe key key *@paramIndex index>=0, 0, 1, second element, and so on; When index<0, -1, the end of the table, the next-to-last element of -2, and so on@return* /
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null; }}/** * put the list in the cache *@paramThe key key *@paramThe value value *@return* /
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false; }}/** * put the list in the cache *@paramThe key key *@paramThe value value *@paramTime Time (seconds) *@return* /
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 the list in the cache *@paramThe key key *@paramThe 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 the list in the cache **@paramThe key key *@paramThe value value *@paramTime 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 list of data according to the index *@paramThe key key *@paramThe index index *@paramThe 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 to value *@paramThe key key *@paramCount removes how many *@paramThe value value *@returnNumber of removals */
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; }}}Copy the code
Testing:
@Autowired
private RedisUtils redisUtils;
@Test
void test2(a){
redisUtils.set("name"."wanli");
redisUtils.del("name");
System.out.println(redisUtils.get("name")); //null
}
Copy the code