redis客户端cluster集群模式整合
一、pom文件引入redis依赖
<!-- redis 版本 --> <redis.version>2.9.0</redis.version> <spring.redis.version>1.8.1.RELEASE</spring.redis.version>
<!-- redis --> <dependency> <groupId>commons-pool</groupId> <artifactId>commons-pool</artifactId> <version>1.5.6</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>${redis.version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>${spring.redis.version}</version> </dependency> </dependencies>
二、redis的可配置化参数
redis.properties配置参数
# JedisPoolConfig的参数 # 最大连接数 redis.pool.maxTotal=30 # 最大空闲时间 redis.pool.maxIdle=10 # 每次最大连接数 redis.pool.numTestsPerEvictionRun=1024 # 释放扫描的扫描间隔 redis.pool.timeBetweenEvictionRunsMillis=30000 # 连接的最小空闲时间 redis.pool.minEvictableIdleTimeMillis=1800000 # 连接控歘按时间多久后释放,当空闲时间>该值且空闲连接>最大空闲连接数时直接释放 redis.pool.softMinEvictableIdleTimeMillis=10000 # 获得链接时的最大等待毫秒数,小于0:阻塞不确定时间,默认-1 redis.pool.maxWaitMillis=1500 # 在获得链接的时候检查有效性,默认false redis.pool.testOnBorrow=true # 在空闲时检查有效性,默认false redis.pool.testWhileIdle=true # 连接耗尽时是否阻塞,false报异常,true阻塞超时,默认true redis.pool.blockWhenExhausted=false # redis集群中的密码 redis.password=han.sun # RedisClusterConfiguration配置 redis.maxRedirects=6 # 主机和端口号 redis.host1=127.0.0.1 redis.port1=7001 redis.host2=127.0.0.1 redis.port2=7002 redis.host3=127.0.0.1 redis.port3=7003 redis.host4=127.0.0.1 redis.port4=7004 redis.host5=127.0.0.1 redis.port5=7005 redis.host6=127.0.0.1 redis.port6=7006
三、spring和redis整合
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.eastrobot.robotdev"/> <!-- 加载配置文件 --> <bean id="annotationPropertyConfigurerRedis" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="order" value="1"/> <property name="ignoreUnresolvablePlaceholders" value="true"/> <property name="locations"> <list> <value>classpath:redis.properties</value> </list> </property> </bean> <!--配置 jedis pool--> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大连接数 --> <property name="maxTotal" value="${redis.pool.maxTotal}"/> <!-- 最大空闲时间 --> <property name="maxIdle" value="${redis.pool.maxIdle}"/> <!-- 每次最大连接数 --> <property name="numTestsPerEvictionRun" value="${redis.pool.numTestsPerEvictionRun}"/> <!-- 释放扫描的扫描间隔 --> <property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}"/> <!-- 连接的最小空闲时间 --> <property name="minEvictableIdleTimeMillis" value="${redis.pool.minEvictableIdleTimeMillis}"/> <!-- 连接空闲按时间多久后释放,当空闲时间大于该值且空闲连接>最大空闲连接数时直接释放 --> <property name="softMinEvictableIdleTimeMillis" value="${redis.pool.softMinEvictableIdleTimeMillis}"/> <!-- 获得连接时的最大等待毫秒数,小于0:阻塞不确定时间,默认-1 --> <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}"/> <!-- 在获得连接的时候检查有效性,默认false --> <property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/> <!-- 在空闲时检查有效性,默认false --> <property name="testWhileIdle" value="${redis.pool.testWhileIdle}"/> <!-- 连接耗尽时是否阻塞,false报异常,true阻塞超时 默认:true--> <property name="blockWhenExhausted" value="${redis.pool.blockWhenExhausted}"/> </bean> <!--配置RedisClusterConfiguration--> <bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration"> <property name="maxRedirects" value="${redis.maxRedirects}"/> <property name="clusterNodes"> <set> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.host1}"/> <constructor-arg name="port" value="${redis.port1}"/> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.host2}"/> <constructor-arg name="port" value="${redis.port2}"/> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.host3}"/> <constructor-arg name="port" value="${redis.port3}"/> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.host4}"/> <constructor-arg name="port" value="${redis.port4}"/> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.host5}"/> <constructor-arg name="port" value="${redis.port5}"/> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.host6}"/> <constructor-arg name="port" value="${redis.port6}"/> </bean> </set> </property> </bean> <!-- Spring-redis连接池管理工厂 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <constructor-arg name="poolConfig" ref="jedisPoolConfig"/> <constructor-arg name="clusterConfig" ref="redisClusterConfiguration"/> <property name="password" value="${redis.password}"/> </bean> <!--redisTemplate--> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <!-- 如果想设置value为对象的话,这里不能配置成StringRedisSerializer --> <!-- 否则会报错 java.lang.ClassCastException: com.eastrobot.robotdev.entity.User cannot be cast to java.lang.String --> <!-- 而是要用JdkSerializationRedisSerializer,然后javabean实现Serializable接口 --> <property name="valueSerializer"> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashValueSerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <!--开启事务 --> <property name="enableTransactionSupport" value="true"/> </bean> </beans>
四、测试
public class ServiceTest extends BaseTest { private static final Logger log = LogManager.getLogger(ServiceTest.class); @Autowired private RedisTemplate<String, String> redisTemplate; @Test public void test1() { ValueOperations<String, String> operations = redisTemplate.opsForValue(); // 存入key-value operations.set("name2", "zhangsan123"); // 根据key取出Value Object name = operations.get("name2"); System.out.println("name2:" + name); // 追加 operations.append("name2", "is man"); name = operations.get("name2"); System.out.println("name2:" + name); // 获得并修改 operations.getAndSet("name2", "xiaoijiqiren"); name = operations.get("name2"); System.out.println("修改后:" + name); } @Test public void boundValueOperations() { String key = "name1"; /* * 先获取redis对value的操作对象,需要先设定key */ BoundValueOperations<String, String> stringTemplate = redisTemplate.boundValueOps(key); //赋值key stringTemplate.set("test123424"); //获取value String value = stringTemplate.get(); System.out.println(key + "的值为:" + value); //从value下标,第0位开始替换原有字符串 stringTemplate.set("test1", 0); String value1 = stringTemplate.get(); System.out.println(key + "的值为:" + value1); //从value下标,第1位开始替换原有字符 stringTemplate.set("test2", 1); String value2 = stringTemplate.get(); System.out.println(key + "的值为:" + value2); //从value下标第7位进行替换,如果超过原有字符串长度,差额中间补齐并且则将原有字符串跟新的进行拼接, stringTemplate.set("test3", 7); String value3 = stringTemplate.get(); System.out.println(key + "的值为:" + value3); /* * 设置value缓存时间 V value, long timeout, TimeUnit unit * 三个字段分别对应 value,缓存时间,缓存单位,例如天,小时等,具体的,看TimeUnit源码 */ //设置超时时间为1天 stringTemplate.set("testTimeout", 1, TimeUnit.DAYS); //获取缓存时间,单位 秒 Long expire = stringTemplate.getExpire(); System.out.println(key + "的缓存时间为:" + expire); } @Test public void testList() { ListOperations<String, String> ops = redisTemplate.opsForList(); List<String> list = new ArrayList<>(); list.add("sunhan"); list.add("lisi"); list.add("xiaoming"); ops.leftPushAll("list1", list); ops.rightPushAll("list2", list); List list1 = ops.range("list1", 0, -1); for (Object o : list1) { log.info("1字段:{}", o); } List list2 = ops.range("list2", 0, -1); for (Object o : list2) { log.info("2字段:{}", o); } } @Test public void testListPop() { ListOperations<String, String> ops = redisTemplate.opsForList(); // 获取到list的长度 log.info("list1长度:{}", ops.size("list1")); log.info("list2长度:{}", ops.size("list2")); // 获取 列表下标的元素,如果下标越界获取的数据为null log.info(ops.index("list1", 1)); // pop取栈头、栈尾 log.info(ops.leftPop("list2")); log.info(ops.rightPop("list2")); // log.info(ops.remove("list2", 0, "sunhan")); } }
五、发生的问题
- 1、spring-data-redis代码进行存储, 客户端却取不到数据
原因:如果key没做序列化存储,实际存进去的key前面会多几个字符,如果你用redis客户端查询你想要的key,
最好在程序里对key进行序列化,这样最终的key值才是你想要的key,redisTemplate下面有这两个属性
<property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property>
@Configuration public class RedisConfig { @Bean JedisConnectionFactory jedisConnectionFactory() { return new JedisConnectionFactory(); } @Bean public <T> RedisTemplate<String, T> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, T> template = new RedisTemplate<String, T>(); template.setConnectionFactory(factory); //1.序列化key template.setKeySerializer(new StringRedisSerializer());//spring自带 //2.序列划value template.setValueSerializer(new RedisObjectSerializer());//自定义 return template; } }