Hello spring data redis

project

learn on project springboot-learning-example

1
git clone https://github.com/JeffLi1993/springboot-learning-example.git

copy module springboot-mybatis-redis to springboot-redis
modify pom.xml, remove mybatis/mysql, add lombok

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>springboot</groupId>
<artifactId>springboot-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-redis :: 使用 Redis 作为缓存</name>

...

<dependencies>

...

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
</dependency>
</dependencies>
</project>

Config

use spring-context.xml define bean in resources

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- redis template definition -->
<bean id="redisTemplate"
class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory"/>

<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="127.0.0.1" p:port="6379" p:password=""
p:poolConfig-ref="jedisPoolConfig" />

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="50" />
<property name="maxIdle" value="50" />
<property name="minIdle" value="10" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
</bean>

</beans>

add annotation in test package

1
2
3
4
5
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/spring-context.xml"})
public class RedisTemplateTest {
...
}

or use application.properties springboot configuration

add annotation in test package

1
2
3
4
5
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisTemplateTest {
...
}

Cluster

add property class

1
2
3
4
5
6
7
8
9
10
11
12
13
@Data
@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {

/*
* spring.redis.cluster.nodes[0] = 127.0.0.1:7379
* spring.redis.cluster.nodes[1] = 127.0.0.1:7380
* ...
*/
List<String> nodes;

}

add springboot bean configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class RedisConfiguration {

@Autowired
ClusterConfigurationProperties clusterProperties;

@Bean("redisTemplateCluster")
public RedisTemplate redisTemplateCluster() {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(
new JedisConnectionFactory(
new RedisClusterConfiguration(clusterProperties.getNodes())));
return template;
}

}

Template

base operate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisTemplateTest {

@Autowired
private RedisTemplate<String, String> redisTemplate;

/**
* Description: 展示String数据结构操作
*/
@Test
public void testValueOperations() {
String key = "RedisTemplateTest:TEST:String:1";
ValueOperations<String, String> valueOp = redisTemplate.opsForValue();
valueOp.set(key, "1");
Assert.assertEquals("1", valueOp.get(key));
redisTemplate.delete(key);
Assert.assertNull(valueOp.get(key));
}

/**
* Description: 展示Set数据结构操作
*/
@Test
public void testSetOperations() {
String key = "RedisTemplateTest:TEST:Set:1";
SetOperations<String, String> op = redisTemplate.opsForSet();
op.add(key, "1", "2");
op.add(key, "2", "3", "4");
op.remove(key, "4");
Assert.assertEquals(Long.valueOf(3), op.size(key));
redisTemplate.delete(key);
Assert.assertEquals(Long.valueOf(0), op.size(key));
}

/**
* Description: 展示SortedSet数据结构操作
*/
@Test
public void testZSetOperations() {
String key = "RedisTemplateTest:TEST:ZSet:1";
ZSetOperations<String, String> op = redisTemplate.opsForZSet();
// 添加Key及用于排序的得分
op.add(key, "1", 1);
op.add(key, "2", 2);
op.add(key, "3", 3);
op.add(key, "4", 2);
// 更新
op.add(key, "4", 4);

Assert.assertEquals(Long.valueOf(2), op.count(key, 3, 4));

op.remove(key, "3");
Assert.assertEquals(Long.valueOf(3), op.size(key));

redisTemplate.delete(key);
Assert.assertEquals(Long.valueOf(0), op.size(key));
}

/**
* Description: 展示Hash数据结构操作
*/
@Test
public void testHashOperations() {
String key = "RedisTemplateTest:TEST:Hash:1";
HashOperations<String, String, String> op = redisTemplate.opsForHash();

op.put(key, "1", "1");

Map<String, String> map = new HashMap<String, String>();
map.put("2", "2");
map.put("3", "3");
map.put("4", "4");
map.put("5", "5");

op.putAll(key, map);
Assert.assertEquals(5, op.entries(key).size());

op.delete(key, "4", "5");
Assert.assertEquals(3, op.entries(key).size());

redisTemplate.delete(key);
Assert.assertEquals(0, op.entries(key).size());
}

}

Repository

POJO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Data
@Builder
@RedisHash("persons")
public class Person {

@Id
String id;
String firstName;
String lastName;
Address address;

}

@Data
public class Address implements Serializable {

public Address() {
}

public Address(String city, String country) {
this.city = city;
this.country = country;
}

String city;
String country;
}

Converter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@WritingConverter
public class AddressToBytesConverter implements Converter<Address, byte[]> {

private final Jackson2JsonRedisSerializer<Address> serializer;

public AddressToBytesConverter() {
serializer = new Jackson2JsonRedisSerializer<Address>(Address.class);
serializer.setObjectMapper(new ObjectMapper());
}

@Override
public byte[] convert(Address value) {
return serializer.serialize(value);
}
}

@ReadingConverter
public class BytesToAddressConverter implements Converter<byte[], Address> {

private final Jackson2JsonRedisSerializer<Address> serializer;

public BytesToAddressConverter() {
serializer = new Jackson2JsonRedisSerializer<Address>(Address.class);
serializer.setObjectMapper(new ObjectMapper());
}

@Override
public Address convert(byte[] value) {
return serializer.deserialize(value);
}
}

Conversions

add conversions in springboot configuration

1
2
3
4
5
@Bean
public CustomConversions redisCustomConversions(){
return new CustomConversions(
Arrays.asList(new AddressToBytesConverter(), new BytesToAddressConverter()));
}

Interface

As our repository extends CrudRepository it provides basic CRUD and finder operations.
The thing we need in between to glue things together is the according Spring configuration.

1
2
3
public interface PersonRepository extends CrudRepository<Person, String> {

}

Test

case:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class RepositoryRedisTemplateTest {

@Autowired
PersonRepository repo;

@Test
public void basicCrudOperations() {
Person lin = Person.builder()
.firstName("lin").address(new Address("JJ", "CHINA")).build();
repo.save(lin);
Assert.assertEquals(lin, repo.findOne(rand.getId()));
Assert.assertEquals(1, repo.count());
repo.delete(lin);
Assert.assertEquals(0, repo.count());
}

}

playground-5:0>hgetall persons:b9d5c6ce-44b1-4d3d-a2dd-8120c794b6f1
1) “_class”
2) “org.spring.springboot.domain.Person”
3) “id”
4) “b9d5c6ce-44b1-4d3d-a2dd-8120c794b6f1”
5) “firstName”
6) “lin”
7) “address”
8) “{“city”:”JJ”,”country”:”CHINA”}”

Redis之序列化POJO
Spring Redis(6)Redis持久化
Redis - How to configure custom conversions
https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#reference
https://docs.spring.io/spring-data/redis/docs/2.0.3.RELEASE/reference/html/#redis.repositories