目录
spring整合spring-data-redis
1. jar包
<!--spring redis相关-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.5.1</version>
</dependency>
<!--redis推荐两种方式的客户端连接redis,lettuce,jedis-->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
<!--哈希映射器-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9.3</version>
</dependency>
Spring Data Redis 与Lettuce和Jedis集成,这两个流行的 Redis 开源 Java 库
2. xml配置
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解-->
<context:component-scan base-package="com.hww"/>
<!--jedis pool-->
<bean id="jedisPool" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="10"></property>
<property name="maxIdle" value="10"></property>
<property name="minIdle" value="2"></property>
<property name="maxWaitMillis" value="15000"></property>
<property name="minEvictableIdleTimeMillis" value="300000"></property>
<property name="numTestsPerEvictionRun" value="3"></property>
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<property name="testOnBorrow" value="true"></property>
<property name="testOnReturn" value="true"></property>
<property name="testWhileIdle" value="true"></property>
</bean>
<!--redis 独立配置-->
<bean id="redisStandaloneConfiguration" class="org.springframework.data.redis.connection.RedisStandaloneConfiguration">
<property name="port" value="6379"></property>
<property name="hostName" value="127.0.0.1"></property>
<!--如果设置了密码则需要配置-->
<!-- <property name="username" value=""></property>
<property name="password" value=""></property>-->
<property name="database" value="0"></property>
</bean>
<bean id="mutableJedisClientConfiguration" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory$MutableJedisClientConfiguration">
<property name="poolConfig" ref="jedisPool"></property>
</bean>
<!--jedisConnectionFactory jedis工厂-->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg name="standaloneConfig" ref="redisStandaloneConfiguration"></constructor-arg>
<constructor-arg name="clientConfig" ref="mutableJedisClientConfiguration"></constructor-arg>
</bean>
<!--redisTemplate-->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<!--序列化-->
<property name="keySerializer" ref="stringRedisSerializer"></property>
<property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
<property name="hashKeySerializer" ref="stringRedisSerializer"></property>
<property name="hashValueSerializer" ref="jdkSerializationRedisSerializer"></property>
</bean>
<!--序列化相关bean-->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
<bean id="jackson2JsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" >
<constructor-arg name="mapper" ref="objectMapper"></constructor-arg>
</bean>
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"></bean>
</beans>
配置
2.1 jedisConnectionFactory 工厂
在构建工厂的时候,需要配置
1. redis服务的相关信息
2. jedis连接池
老版本的配置如下:所有的东西都是直接配置到JedisConnectionFactory
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="127.0.0.1" />
<property name="port" value="6379" />
<!-- <property name="password" value="${redis.pass}" /> -->
<property name="database" value="1" />
<property name="poolConfig" ref="redisPoolConfig" />
</bean>
新版版本中,构造方法
很多的配置都已经用@deprecated标志了,所以需要新的方式去构建jedisConnectionFactory
2.2 redisTemplate
2.2.1 序列化
Redis是二进制安全的, 存储的数据只有字节。虽然 Redis 本身支持各种类型,但在大多数情况下,这些类型指的是数据的存储方式,而不是它所代表的内容。由用户决定是否将信息转换为字符串或任何其他对象。
意思就是说redis支持向 spring list set map等这些类型,但是这些类型在redis中存储都是以二进制的方式进行存储的。
当我们存储完成后,登录redis客户端查看,发现存储的数据是乱码。其实是二进制存储的。那么如果想让二进制的方式变的可读性好一点,需要配置序列化
有几种方式可以实现:
-
JdkSerializationRedisSerializer
,默认情况下用于RedisCache
和RedisTemplate
。对于hash结构的依然是乱码
-
StringRedisSerializer,对于spring类型的没问题。但是如果涉及的int等不是spring类型的就会报 类型转换异常
-
Jackson2JsonRedisSerializer
或GenericJackson2JsonRedisSerializer
用于以JSON格式存储数据,如果是这个就可以转换成json格式的。
2.2.2 StringRedisTemplate
redis中提供了一个StringRedisTemplate的简单封装
<!--StringRedisTemplate-->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"></bean>
这是构造方法,提供了一个对String 的封装。与StringRedisSerializer是一样的。
3. 使用redis
package com.hww.redis;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.hash.HashMapper;
import org.springframework.data.redis.hash.Jackson2HashMapper;
import org.springframework.data.redis.hash.ObjectHashMapper;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class RedisDemo {
@Autowired
RedisTemplate redisTemplate;
@Autowired
ObjectMapper objectMapper;
/**
* 简单的key value
*/
public void redisDemo(){
redisTemplate.opsForValue().set("hello3","world3");
System.out.println(redisTemplate.opsForValue().get("hello2"));
}
/**
* 哈希结构的存储key field value
*/
public void redisHashDemo02(){
redisTemplate.opsForHash().put("person01","name","zhangsan");
redisTemplate.opsForHash().put("person01","age",11);
System.out.println(redisTemplate.opsForHash().get("person01","name"));
}
/**
* 哈希存储,map结构
*/
public void redisHashDemo03(){
Person person = new Person("lisi", 22);
Jackson2HashMapper jackson2HashMapper = new Jackson2HashMapper(objectMapper,false);
Map<String, Object> stringObjectMap = jackson2HashMapper.toHash(person);
redisTemplate.opsForHash().putAll("person02",stringObjectMap);
Map person02 = redisTemplate.opsForHash().entries("person02");
Object o = jackson2HashMapper.fromHash(person02);
System.out.println(o.getClass());
System.out.println(o);
}
}
3.1 hash映射器
java是面向对象的,我们希望在存储时能够将对象直接存储到redis中,而不是利用hash每次都需要存储每个field的值。
所以提供一种方式Jackson2HashMapper 将对象转换成map,进行hash存储
将获取的值转换成一个对象
Jackson2HashMapper jackson2HashMapper = new Jackson2HashMapper(objectMapper,false); Map<String, Object> stringObjectMap = jackson2HashMapper.toHash(person); redisTemplate.opsForHash().putAll("person02",stringObjectMap); Map person02 = redisTemplate.opsForHash().entries("person02"); Object o = jackson2HashMapper.fromHash(person02);
4. 测试类
package com.hww;
import com.hww.redis.RedisDemo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-application.xml")
public class MyTest {
@Autowired
RedisDemo redisDemo;
@Test
public void myTest(){
redisDemo.redisDemo();
}
@Test
public void myTest02(){
redisDemo.redisHashDemo02();
}
@Test
public void myTest03(){
redisDemo.redisHashDemo03();
}
}
5. redis 主从对写分离
6. spring 哨兵支持
需要提前配置好redis服务 和 sentinel哨兵服务
配置sentinel哨兵集群,配置主master redis服务
<!--开启注解-->
<context:component-scan base-package="com.hww"/>
<!--jedis pool-->
<bean id="jedisPool" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="10"></property>
<property name="maxIdle" value="10"></property>
<property name="minIdle" value="2"></property>
<property name="maxWaitMillis" value="15000"></property>
<property name="minEvictableIdleTimeMillis" value="300000"></property>
<property name="numTestsPerEvictionRun" value="3"></property>
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<property name="testOnBorrow" value="true"></property>
<property name="testOnReturn" value="true"></property>
<property name="testWhileIdle" value="true"></property>
</bean>
<bean id="sentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
<!--master配置-->
<property name="master">
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="2001"></constructor-arg>
<property name="name" value="mymaster"></property>
</bean>
</property>
<!--sentinel 监控集群-->
<property name="sentinels">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="3001"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="3002"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="3003"></constructor-arg>
</bean>
</set>
</property>
</bean>
<!--jedisConnectionFactory jedis工厂-->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPool"></constructor-arg>
</bean>
<!--redisTemplate-->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<!--序列化-->
<property name="keySerializer" ref="stringRedisSerializer"></property>
<property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
<property name="hashKeySerializer" ref="stringRedisSerializer"></property>
<property name="hashValueSerializer" ref="jackson2JsonRedisSerializer"></property>
</bean>
<!--序列化相关bean-->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
<bean id="jackson2JsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" >
<constructor-arg name="mapper" ref="objectMapper"></constructor-arg>
</bean>
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"></bean>
<!--StringRedisTemplate-->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
</bean>
redis主从读写分离
如果用的是 lettuce 客户端,那么读写分离有相关的配置
如果用jedis客户端,那么读写分离则需要自己实现。
7.redis 集群
配置,跟之前的单点配置是没有多区别的,只是在创建JedisConnectionFactory时,参数不一样。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解-->
<context:component-scan base-package="com.hww"/>
<!--jedis pool-->
<bean id="jedisPool" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="10"></property>
<property name="maxIdle" value="10"></property>
<property name="minIdle" value="2"></property>
<property name="maxWaitMillis" value="15000"></property>
<property name="minEvictableIdleTimeMillis" value="300000"></property>
<property name="numTestsPerEvictionRun" value="3"></property>
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<property name="testOnBorrow" value="true"></property>
<property name="testOnReturn" value="true"></property>
<property name="testWhileIdle" value="true"></property>
</bean>
<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="maxRedirects" value="5"></property>
<property name="clusterNodes">
<set>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="6379"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="6380"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="6381"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="36379"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="36380"></constructor-arg>
</bean>
<bean class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="127.0.0.1"></constructor-arg>
<constructor-arg name="port" value="36381"></constructor-arg>
</bean>
</set>
</property>
</bean>
<!--jedisConnectionFactory jedis工厂-->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg name="clusterConfig" ref="redisClusterConfiguration"></constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPool"></constructor-arg>
</bean>
<!--redisTemplate-->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<!--序列化-->
<property name="keySerializer" ref="stringRedisSerializer"></property>
<property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
<property name="hashKeySerializer" ref="stringRedisSerializer"></property>
<property name="hashValueSerializer" ref="jackson2JsonRedisSerializer"></property>
</bean>
<!--序列化相关bean-->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
<bean id="jackson2JsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" >
<constructor-arg name="mapper" ref="objectMapper"></constructor-arg>
</bean>
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"></bean>
<!--StringRedisTemplate-->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
</bean>
</beans>
8.redis 事务
8.1 redis事务
/**
* 事务
*/
public void redisExe(){
redisTemplate.execute(new SessionCallback() {
public Object execute(RedisOperations redisOperations) throws DataAccessException {
//开启事务
redisOperations.multi();
redisOperations.opsForValue().set("myHello","myWorld");
redisOperations.opsForValue().set("k1","东方");
redisOperations.opsForValue().set("k1","西门");
redisOperations.delete("myHello");
//执行事务
List exec = redisOperations.exec();
System.out.println(exec);
return exec;
}
});
}
8.2 spring 整合redis事务
配置
1. 在redis中配置enableTransactionSupport 为true开启事务
<property name="enableTransactionSupport" value="true"></property>
2. 开启spring事务管理器,开启注解事务
3,此时,Spring Data Redis可以使用现有的事务管理器参与事务
<!--redisTemplate-->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
<!--开启Redis事务-->
<property name="enableTransactionSupport" value="true"></property>
<!--序列化-->
<property name="keySerializer" ref="stringRedisSerializer"></property>
<property name="valueSerializer" ref="jdkSerializationRedisSerializer"></property>
<property name="hashKeySerializer" ref="stringRedisSerializer"></property>
<property name="hashValueSerializer" ref="jackson2JsonRedisSerializer"></property>
</bean>
<!--序列化相关bean-->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
<bean id="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"></bean>
<bean id="jackson2JsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" >
<constructor-arg name="mapper" ref="objectMapper"></constructor-arg>
</bean>
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"></bean>
<!--StringRedisTemplate-->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"></property>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="password" value=""></property>
<property name="username" value=""></property>
<property name="url" value=""></property>
<property name="driverClassName" value=""></property>
</bean>
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开始事务注解 @Transactional-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
配置事务
@Transactional
public void transactionDemo(){
。。。。。
}
9.redis 发布订阅
9.1 发布
要发布消息,您可以像其他操作一样使用低级RedisConnection
或高级RedisTemplate
. 这两个实体都提供了该publish
方法,该方法接受消息和目标通道作为参数。
只需要设置一个通道名称,将messag放入即可。
package com.hww.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class RedisPubSubDemo {
@Autowired
StringRedisTemplate restTemplate;
/**
* 发布消息
*/
public void pubDemo(){
restTemplate.convertAndSend("channel01","hello");
}
}
可以通过客户端连接redis,
psubscribe channel01 监听该通道。
127.0.0.1:2001> PSUBSCRIBE channel01
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel01"
3) (integer) 1
1) "pmessage"
2) "channel01"
3) "channel01"
4) "hello"
1) "pmessage"
2) "channel01"
3) "channel01"
4) "hello"
9.2 订阅
在接收端,可以通过直接命名或使用模式匹配来订阅一个或多个频道。后一种方法非常有用,因为它不仅允许使用一个命令创建多个订阅
1. 消息监听MessageListener
2. 消息侦听器容器RedisMessageListenerContainer
3. 消息处理MessageListenerAdapter,这个处理类需要自己实现,
<!--设置监听-->
<!--MessageListenerAdapter类是Spring的异步支持消息的最后一个组件-->
<bean id="messageHandle" class="com.hww.redis.MessageHandle"></bean>
<!--为了订阅消息,需要实现MessageListener回调。每次有新消息到达时,
都会调用回调并通过该onMessage方法运行用户代码。该接口不仅可以访问实际消息,
还可以访问通过它接收到的通道以及订阅用于匹配通道的模式(如果有)。
此信息使被调用者不仅可以通过内容而且还可以检查其他详细信息来区分各种消息。-->
<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg name="delegate" ref="messageHandle"></constructor-arg>
</bean>
<!--消息侦听器容器
RedisMessageListenerContainer充当消息侦听器容器。
它用于从 Redis 通道接收消息并驱动MessageListener注入其中的实例-->
<bean id="redisContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<property name="messageListeners">
<map>
<entry key-ref="messageListener">
<bean class="org.springframework.data.redis.listener.ChannelTopic">
<constructor-arg value="channel01"/>
</bean>
</entry>
</map>
</property>
</bean>
package com.hww.redis;
public class MessageHandle {
public void handleMessage(String message){
System.out.println(message);
}
}
测试
这个可以写了一各while循环,让服务等着,然后通过命令redis-cli 连接redis服务,发布一个消息,看是否能否接收到
package com.hww;
import com.hww.redis.RedisDemo;
import com.hww.redis.RedisPubSubDemo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-application03.xml")
public class MyTest4 {
@Autowired
RedisPubSubDemo redisPubSubDemo;
@Test
public void myTest02(){
while(true){
}
}
}