一、首先要下载一个redis服务器(Windows版)
1.下载安装
下载地址 : https://github.com/MSOpenTech/redis/releases
下载好之后直接解压文件 绿色免安装
推荐把redis路径设在path中
这样打开cmd 界面就可以直接打开了,不用每次都要输入路径了
自己遇到一个问题就是必须要把redis.windows.conf文件拷贝到自己系统的根路径中,很郁闷
将redis.windows.conf放到C:\Users\82745 下
否则直接使用下面的命令无法启动 报错:加载不到redis.windows.conf文件
这里也可以安装 RedisDesktopManager,启动Redis服务之后,可以直接使用此redis桌面管理工具连接redis服务端方便操作
2.启动基本命令
启动服务命令 redis-server.exe redis.windows.conf
后面的redis.windows.conf 即为redis的配置文件
出现如上界面表示redis服务端启动成功,保持此界面不要关闭,(这里没有修改配置文件,可修改为后台运行)
重新打开一个命令窗口
输入命令redis-cli 打开客户端 命令 如下
如果在conf中设立了redis密码,则可使用auth 密码登录,不设置也可以正常使用
现在可以简单的先测试一下redis
放入一个值 set myKey xiazhang(最简单的存命令为 set key value)
然后取出 get myKey 结构为 xiazhang,
redis安装测试成功
二、spring框架集成redis
1.导入jar包
我开始使用的是下面两个版本
jedis-2.2.0.jar 最后使用的是jedis-2.6.0
spring-data-jedis.1.4.1.jar
2. 配置redis
a. 配置redis.properties文件
#redis server ip redis.host=127.0.0.1 redis.port=6379 redis.password=xiazhang #redis.database=3 redis.maxIdle=300 redis.maxActive=600 redis.maxWait=1000 redis.testOnBorrow=true
并记得在spring applicationContext.xml文件中引入该配置文件
<!-- 引入本地配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> <value>classpath:redis.properties</value> </list> </property> </bean>
b. 在applicationContext-datasource.xml文件中配置redis
这里为最终的正确配置
当然也可以单独在特定文件中配置如applicationContext-redis.xml,但是个人感觉这个配置不是很多所以放到一个文件中,方便管理
<!-- redis 配置开始 --> <!-- redis连接池 --> <beans:bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- 最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制。 --> <beans:property name="maxIdle" value="${redis.maxIdle}" /> <!-- 连接池的最大数据库连接数。设为0表示无限制 --> <beans:property name="maxTotal" value="${redis.maxActive}" /> <!-- 最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制 --> <beans:property name="maxWaitMillis" value="${redis.maxWait}" /> <!-- 在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的 --> <beans:property name="testOnBorrow" value="${redis.testOnBorrow}" /> </beans:bean> <!-- redis 连接工厂 --> <bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}"/> <property name="port" value="${redis.port}"/> <property name="password" value="${redis.password}"/> <property name="timeout" value="15000"/> <!-- <beans:property name="database" value="${redis.database}"/> --> <property name="poolConfig" ref="jedisPoolConfig"/> </bean> <!-- redis操作模板,这里采用尽量面向对象的模板 --> <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="redisConnectionFactory"/> <!-- 如果不配置Serializer,那么存储的时候只能使用String,如果用对象类型存储,那么会提示错误 can't cast to String --> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <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.JdkSerializationRedisSerializer"/> </property> </bean> <!-- redis 配置结束 -->
配置结束
3.从开始遇到的问题
报错:
java.lang.NoClassDefFoundError: org/apache/commons/pool2/impl/GenericObjectPoolConfig
(高版本jedis需要使用commons-pool2 ),缺少jar包:导入commons-pool2 jar包
继续启动工程
错误 java.lang.VerifyError: (class: org/springframework/data/redis/connection/jedis/JedisConnectionFactory, method: createRedisPool signature: ()Lredis/clients/util/Pool;) Incompatible argument to function
jedis 和 spring-data-jedis jar包 冲突 更换jedis.jar 版本
注意 : 这里有一个大坑
jar包冲突所以更换jar包 于是找了一个最新的jedis-2.9.0.jar
于是报错
nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'maxActive' of bean class [redis.clients.jedis.JedisPoolConfig]: Bean property 'maxActive' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
提示JedisPoolConfig没有maxActive属性
查看源码
package redis.clients.jedis; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; public class JedisPoolConfig extends GenericObjectPoolConfig { public JedisPoolConfig() { // defaults to make your life with connection pool easier :) setTestWhileIdle(true); setMinEvictableIdleTimeMillis(60000); setTimeBetweenEvictionRunsMillis(30000); setNumTestsPerEvictionRun(-1); } }
再继续查看GenericObjectPoolConfig类所在的jar包,果然没有
jedis包括2.4.1,2.5.1等高版本的JedisPoolConfig没有maxActive属性,不能按照网上那些方式去配置Redis了,网上大部分搜索出来的redis配置都是基于旧版本的jedis,在jedis新版本,JedisPoolConfig没有maxActive属性,JedisPoolConfig没有maxWait属性,以及被替换成其他的命名。
其实高版本的jedis使用了org.apache.commons.pool2.impl.GenericObjectPoolConfig。dbcp的修改日志显示:change "maxActive" -> "maxTotal" and "maxWait" -> "maxWaitMillis" in all examples.所以高版本jedis配置JedisPoolConfig的maxActive,maxWait应该为:
原<beans:property name="maxActive" value="${redis.maxActive}" />
<beans:property name="maxWait" value="${redis.maxWait}" />
改为
<property name="maxTotal" value="${redis.pool.maxActive}"/>
<property name="maxWaitMillis" value="${redis.pool.maxWait}"/>
然后启动工程还是报错 不过已经跳过了刚刚的
Error creating bean with name 'redisConnectionFactory' defined in class path resource [applicationContext-datasource.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'pool' of bean class [org.springframework.data.redis.connection.jedis.JedisConnectionFactory]:Bean property 'pool' is not writable or has an invalid setter method. Did you mean 'port'?
<property name="pool" ref="poolConfig"/> 这里错误
查看JedisConnectionFactory源码 发现又改动了 你大爷
private Pool<Jedis> pool;
private JedisPoolConfig poolConfig = new JedisPoolConfig();
pool 已经不是那个pool了 然而poolConfig 还是那个JedisPoolConfig 所以应该使用 poolConfig替换pool
即<property name="pool" ref="jedisPoolConfig"/>
应改为
<property name="poolConfig" ref="jedisPoolConfig"/>
continue!!!
于是又报错了
Caused by: java.lang.NoSuchMethodError: redis.clients.jedis.JedisShardInfo.setTimeout(I)V(你大爷的 算了 等会出去吃饭吧)
源码中 timeout 是有默认值的 private int timeout = Protocol.DEFAULT_TIMEOUT;肯定不是配置错误
难道是我用的jedis版本是最新的吗 jedis-2.9.0.jar 换成 jedis-2.6.0 果然好了 这里几个错误折腾了好久
4.测试
激动人心的时候到了
启动redis 服务器 测试一下
新建RedisService接口
package com.mvc.redis.service; /** * redis 操作接口层 * * @author xiazhang * @date 2017-6-16 */ public interface RedisService { /** * 通过key删除 * * @param key */ public abstract long del(String... keys); /** * 添加key value 并且设置存活时间(byte) * * @param key * @param value * @param liveTime */ public abstract void set(byte[] key, byte[] value, long liveTime); /** * 添加key value 并且设置存活时间 * * @param key * @param value * @param liveTime * 单位秒 */ public abstract void set(String key, String value, long liveTime); /** * 添加key value * * @param key * @param value */ public abstract void set(String key, String value); /** * 添加key value (字节)(序列化) * * @param key * @param value */ public abstract void set(byte[] key, byte[] value); /** * 获取redis value (String) * * @param key * @return */ public abstract String get(String key); /** * 通过正则匹配keys * * @param pattern * @return * @return */ // public abstract Setkeys(String pattern); /** * 检查key是否已经存在 * * @param key * @return */ public abstract boolean exists(String key); /** * 清空redis 所有数据 * * @return */ public abstract String flushDB(); /** * 查看redis里有多少数据 */ public abstract long dbSize(); /** * 检查是否连接成功 * * @return */ public abstract String ping(); }
接口实现类 RedisServerImpl
package com.mvc.redis.service.impl; import java.io.UnsupportedEncodingException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import com.mvc.redis.service.RedisService; @Service(value="redisService") public class RedisServiceImpl implements RedisService{ private static String redisCode = "utf-8"; @Autowired private RedisTemplate redisTemplate; /** * @param key */ public long del(final String... keys) { return redisTemplate.execute(new RedisCallback() { public Long doInRedis(RedisConnection connection) throws DataAccessException { long result = 0; for (int i = 0; i < keys.length; i++) { result = connection.del(keys[i].getBytes()); } return result; } }); } /** * @param key * @param value * @param liveTime */ public void set(final byte[] key, final byte[] value, final long liveTime) { redisTemplate.execute(new RedisCallback() { public Long doInRedis(RedisConnection connection) throws DataAccessException { connection.set(key, value); if (liveTime > 0) { connection.expire(key, liveTime); } return 1L; } }); } /** * @param key * @param value * @param liveTime */ public void set(String key, String value, long liveTime) { this.set(key.getBytes(), value.getBytes(), liveTime); } /** * @param key * @param value */ public void set(String key, String value) { this.set(key, value, 0L); } /** * @param key * @param value */ public void set(byte[] key, byte[] value) { this.set(key, value, 0L); } /** * @param key * @return */ public String get(final String key) { return redisTemplate.execute(new RedisCallback() { public String doInRedis(RedisConnection connection) throws DataAccessException { try { return new String(connection.get(key.getBytes()), redisCode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } }); } /** * @param pattern * @return */ // public Setkeys(String pattern) { // return redisTemplate.keys(pattern); // // } /** * @param key * @return */ public boolean exists(final String key) { return redisTemplate.execute(new RedisCallback() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { return connection.exists(key.getBytes()); } }); } /** * @return */ public String flushDB() { return redisTemplate.execute(new RedisCallback() { public String doInRedis(RedisConnection connection) throws DataAccessException { connection.flushDb(); return "ok"; } }); } /** * @return */ public long dbSize() { return redisTemplate.execute(new RedisCallback() { public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.dbSize(); } }); } /** * @return */ public String ping() { return redisTemplate.execute(new RedisCallback() { public String doInRedis(RedisConnection connection) throws DataAccessException { return connection.ping(); } }); } private RedisServiceImpl() { } }
新建测试类
package com.mvc.redis; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mvc.redis.service.RedisService; /** * redis 测试 * * @author xiazhang * @date 2017-6-15 */ public class RedisTest{ ApplicationContext app = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); RedisService redisService = (RedisService) app.getBean("redisService"); @Test public void del() { redisService.set("xia", "xia"); long result = redisService.del("xia"); Assert.assertEquals(1L, result); } @Before @Test public void set() { redisService.set("zhang", "zhang"); } @After @Test public void get() { Assert.assertEquals("zhang", redisService.get("zhang")); } }
最终的结构为
测试成功