Article Directory
1. Java client of Redis
The following are the top five Java clients recommended by redis.io official website
Java client | features |
---|---|
Jedis | Using the Redis command as the method name, the learning cost is low, simple and practical, but the Jedis instance is not thread-safe, and it needs to be used based on the connection pool in a multi-threaded environment |
lettuce | Lettuce is implemented based on Netty, supports synchronous, asynchronous and responsive programming, and is thread-safe. Support Redis sentinel mode, cluster mode and pipeline mode |
Redisson | Redisson is a distributed and scalable Java data structure collection based on Redis. Contains many powerful tools such as Map, Queue, Lock, Semaphore, AtomicLong, etc. |
2. Jedis
Create a Maven project
1.pom.xml to introduce jedis dependencies, and by the way, also introduce junit dependencies:
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
2. Establish connection:
3. Test
@Test
void testString() {
// 往redis插入数据
String result = jedis.set("name","zd");
System.out.println("result = " + result);
// 获取数据
String name = jedis.get("name");
System.out.println("name = " + name);
}
4. Release resources:
@AfterEach
void tearDown() {
if(jedis != null) {
jedis.close();
}
}
Let's operate a Hash type again:
@Test
void testHash() {
// 插入 Hash 数据
jedis.hset("user:1","name","zd");
jedis.hset("user:1","age","18");
// 获取 Hash 数据
Map<String, String> map = jedis.hgetAll("user:1");
System.out.println(map);
}
Jedis connection pool
Jedis itself is not thread-safe, and frequently creating and destroying connections will cause performance loss, so we recommend that you use the Jedis connection pool instead of the direct connection method of Redis
Write the tool class of Redis:
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static {
// 配置连接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(8);
jedisPoolConfig.setMaxIdle(8);
jedisPoolConfig.setMinIdle(0);
jedisPoolConfig.setMaxWaitMillis(1000);
// 创建连接池对象
jedisPool = new JedisPool(jedisPoolConfig,
"127.0.0.1",6379,1000,"123456");
}
public static Jedis getJedis() {
return jedisPool.getResource();
}
}
When we go to close() again, it is not really closed, but the resource is returned to the Redis connection pool, and it is
no problem for us to execute it again
3. Spring Data Redis
SpringData is a data operation module in Spring, including the integration of various databases. The integration module for Redis is called SpringDataRedis, the official website address: Spring Data
Spring Data Redis has the following characteristics:
- Provides integration of different Redis clients (Lettuce and Jedis)
- Provides RedisTemplate unified API to operate Redis
- Support Redis publish-subscribe model
- Supports Redis Sentinel and Redis Cluster
- Support Responsive Programming based on Lettuce
- Supports data serialization and deserialization based on JDK, JSON, strings, and Spring objects
- Support Redis-based JDKCollection implementation
Spring Data Redis Quick Start
The RedisTemplate tool class is provided in SpringDataRedis, which encapsulates various operations on Redis. And encapsulate the operation API of different data types into different types
API | return value | illustrate |
---|---|---|
redisTemplate.opsForValue() | ValueOperations | Operate String type data |
redisTemplate.opsForHash() | HashOperations | Operate Hash type data |
redisTemplate.opsForList() | ListOperations | Operate List type data |
redisTemplate.opsForSet() | SetOperations | Operate Set type data |
redisTemplate.opsForZSet | ZSetOperations | Operate SortedSet type data |
redisTemplate | Operate common commands |
Our SpringBoot already provides support for SpringBootRedis, which is very simple to use:
1. Introduce dependencies:
<!--Redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--连接池依赖-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2. Configuration file:
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
lettuce:
pool:
max-active: 8 #最大连接
max-idle: 8 #最大空闲连接
min-idle: 0 #最小空闲连接
max-wait: 1000 #连接等待时间
3. Inject the RedisTemplate object and write the test code:
@SpringBootTest
class SpringDataRedisDemoApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
// 写入一条String数据
redisTemplate.opsForValue().set("name","小王");
Object name = redisTemplate.opsForValue().get("name");
System.out.println(name);
}
}
SpringDataRedis serialization method
Why is it that we have already operated, but the name in Redis has not been modified?
RedisTemplate can receive any Object as a value and write it to Redis, but it will serialize the Object into bytes before writing. The default is JDK serialization, and the result is as follows:
There are some problems with this:Poor readability and large memory usage
We can customize the serialization method of RedisTemplate:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory) {
// 创建RedisTemplate对象
RedisTemplate<String,Object> template = new RedisTemplate<>();
// 设置连接工厂
template.setConnectionFactory(connectionFactory);
// 创建JSON序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// 设置key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// 设置Value的序列化
template.setValueSerializer(jsonRedisSerializer);
template.setHashValueSerializer(jsonRedisSerializer);
// 返回 RedisTemplate对象
return template;
}
}
We found that an error was reported because we did not introduce jackson dependencies:
<!--Jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
The execution is successful, let's take a look at the Redis database again
. The string is ok, let's try to see if the object can be serialized correctly for us
// 创建一个Sudent类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private String name;
private Integer age;
}
test:
@Test
void testSaveStudent() {
// 写入数据
redisTemplate.opsForValue().set("student",new Student("小王",18));
//获取数据
Student student = (Student) redisTemplate.opsForValue().get("student");
System.out.println("student: " + student);
}
We can find that when we save the object, it helps us serialize it into a Json string, and when we fetch the data, it helps us deserialize it into a Java object, but in this way, the Json serializer will write the class type of the class into the json result. Entering Redis will bring additional memory overhead
In order to save memory space, we will not actually use the JSON serializer to process the value, but use the String serializer uniformly, requiring only the key and value of the String type to be stored. When it is necessary to store Java objects, it must be done manually
StringRedisTemplate
Spring provides a StringRedisTemplate class by default, and the serialization method of its key and value is String by default. save us
@Autowired
private StringRedisTemplate stringRedisTemplate;
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testStringRedisTemplate() throws JsonProcessingException {
Student student = new Student("小王",18);
// 手动序列化
String json = mapper.writeValueAsString(student);
// 写入数据到redis
stringRedisTemplate.opsForValue().set("student",json);
//读取数据
String val = stringRedisTemplate.opsForValue().get("student");
// 手动反序列化
Student student1 = mapper.readValue(val,Student.class);
System.out.println("student1: " + student1);
}
Two serialization methods of RedisTemplate:
Method 1:
- Custom RedisTemplate
- Modify the serializer of RedisTemplate to GenericJackson2JsonRedisSerializer
Method 2:
- Use StringRedisTemplate
- When writing to Redis, manually serialize the object to JSON
- When reading Redis, manually deserialize the read JSON into an object
Hash operation
We can find that when we want to operate the Hash type, we find that there is no hset() method, because we are using a map operation similar to Java.
put is equivalent to hset, putAll is equivalent to hmset
Other methods are similar
@Test
void testHash() {
stringRedisTemplate.opsForHash().put("student","name","小王");
stringRedisTemplate.opsForHash().put("student","age","18");
Map<Object, Object> student = stringRedisTemplate.opsForHash().entries("student");
System.out.println("student: " + student);
}