## Spring Data Redis 实战
redis 介绍
redis是使用ANSI C 编写的NOSQL数据库,并提供领域专用语言DSL。其采用客户端/服务器端模式,监听TCP端口并接收命令。客户端发送命令:
SET foo bar
或
LPUSH mylist val
命令在一个key上执行原子操作,读写一个或多个key值。没有任何竞争条件发生,不需要任何锁机制。redis所有基于key的操作,值都保存在内存中。
redis应用场景
基于内存数据,提升数据库处理效率,特别是有大量写操作,实时统计分析。
实现与memcached一样的缓存功能,但可以修改缓存数据,而不仅是缓存失效。
实现消息功能,redis list可作为队列,实现发布/订阅消息。
计算单元,在redis实例中实现复杂的计算操作,如实现推荐算法引擎。
Spring Data Redis 及 redis 连接器
Spring Data 集成Jedis、JRedis、srp以及Lettuce连接器。在不同连接器之间仅有一组接口保持行为一致性。RedisConnection 和 RedisConnectionFactory 用于从redis中获取活动连接。同时RedisConnectionFactory也处理和后端redis之间的通讯以及把库异常翻译为Spring一致的Dao异常层级,方便在不同连接器间可以不修改代码进行切换。
依赖
Spring data Redis可以支持不同连接器,但好处是只要你的代码基于Spring data Redis api,则与你是用那个连接器无关。你可以通过依赖自由切换连接器。
示例使用jedis连接器:
plugins {
id 'org.springframework.boot' version '2.1.2.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
repositories {
mavenCentral()
}
dependencies {
compile 'redis.clients:jedis:2.9.0'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'
}
其中 jackson-databind 实现对象序列化功能。
jedis 连接器基本配置示例
Spring Boot java 配置:
@Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisCfg= new RedisStandaloneConfiguration();
redisCfg.setHostName("localhost");
redisCfg.setPort(6379);
redisCfg.setPassword("8888");
return new JedisConnectionFactory(redisCfg);
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
template.setValueSerializer(jacksonSerializer);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
这里指定jackson的ObjectMapper作为序列化工具,实现对象自动转成json字符串进行传输和存储。
基本类型交互
// ValueOperations, BoundValueOperations
stringRedisTemplate.opsForValue().set(key, value);
stringRedisTemplate.boundValueOps(key).set(value);
// HashOperations, BoundHashOperations
stringRedisTemplate.opsForHash().put(key, "hashKey", value);
stringRedisTemplate.boundHashOps(key).put("hashKey", value);
// ListOperations, BoundListOperations
stringRedisTemplate.opsForList().leftPush(key, value);
stringRedisTemplate.opsForList().rightPush(key, value);
stringRedisTemplate.opsForList().rightPop(key, 1, TimeUnit.SECONDS);
stringRedisTemplate.opsForList().leftPop(key, 1, TimeUnit.SECONDS);
stringRedisTemplate.boundListOps(key).leftPush(value);
stringRedisTemplate.boundListOps(key).rightPush(value);
stringRedisTemplate.boundListOps(key).rightPop(1, TimeUnit.SECONDS);
stringRedisTemplate.boundListOps(key).leftPop(1, TimeUnit.SECONDS);
// ZSetOperations, BoundZSetOperations
stringRedisTemplate.opsForZSet().add(key, "player1", 12.0d);
stringRedisTemplate.opsForZSet().add(key, "player2", 11.0d);
stringRedisTemplate.boundZSetOps(key).add("player1", 12.0d);
stringRedisTemplate.boundZSetOps(key).add("player2", 11.0d);
自定义类型操作
自定义类型Student类:
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student implements Serializable {
public enum Gender {
/**
* male
*/
MALE,
/**
* female
*/
FEMALE
}
private String id;
private String name;
private Gender gender;
private int grade;
}
存储获取student对象:
Student student = new Student("Eng2015002", "John Doe", Student.Gender.MALE, 1);
redisTemplate.opsForValue().set(student.getId(),student);
Object stu = redisTemplate.opsForValue().get(student.getId());
log.info("Eng2015002:{}", stu);
jackson自动进行序列化和反序列化。
内置类
Spring Data Redis 提供了几个可重用组件,如原子计数器和集合。原子计数器可以方便实现Redis自增key,而集合可以实现redis key的管理:
原子计数器示例
@Bean
public RedisAtomicInteger init(RedisConnectionFactory factory) {
return new RedisAtomicInteger("myCounter", factory);
}
public class Example {
@Autowired
private RedisAtomicInteger atomicInteger;
public void increment() {
atomicInteger.incrementAndGet();
}
}
Redis 集合示例
@Bean
public Deque<String> queue(StringRedisTemplate redisTemplate) {
return new DefaultRedisList<>(
redisTemplate.boundListOps("MY_KEY_FOR_QUEUE"));
}
public class DequeExample {
@Resource(name = "queue")
private Deque<String> queue;
public void add(String value) {
queue.add(value);
}
public String getFirst() {
return queue.getFirst();
}
public String getLast() {
return queue.getLast();
}
}
发布/订阅模型
Spring Data Redis 支持基于主题的发布订阅模型:
监听器及主题配置:
@Configuration
public class RedisMessageConfig {
@Autowired
private JedisConnectionFactory jedisConnectionFactory;
@Bean
RedisMessageListenerContainer redisContainer() {
RedisMessageListenerContainer container
= new RedisMessageListenerContainer();
container.setConnectionFactory(jedisConnectionFactory);
container.addMessageListener(messageListener(), topic());
return container;
}
@Bean
MessageListenerAdapter messageListener() {
return new MessageListenerAdapter(new RedisMessageSubscriber());
}
@Bean
ChannelTopic topic() {
return new ChannelTopic("messageQueue");
}
}
实际处理订阅逻辑代码:
@Service
public class RedisMessageSubscriber implements MessageListener {
public static List<String> messageList = new ArrayList<>();
@Override
public void onMessage(Message message, byte[] pattern) {
messageList.add(message.toString());
System.out.println("Message received: " + message.toString());
}
}
发送消息类:
@Service
public class RedisMessagePublisher implements MessagePublisher {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ChannelTopic topic;
public RedisMessagePublisher(RedisTemplate<String, Object> redisTemplate, ChannelTopic topic) {
this.redisTemplate = redisTemplate;
this.topic = topic;
}
@Override
public void publish(Object message) {
redisTemplate.convertAndSend(topic.getTopic(), message);
}
}
总结
本文介绍了redis 及 spring data redis。通过示例展示spring data redis和redis 交互,同时也介绍常用内置组件,实现原子计数器、队列以及订阅/发布模型。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/87970540