github地址:https://github.com/jiangcaijun/ssm
2017-05-23(添加spring与redis整合)
github版本号
1、添加maven下依赖
<!-- config redis data and client jar-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.1.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
注意:起初,我将redis.clients jedis的version设为 2.1.0 ,导致jedis.close()方法不存在。将其版本号升高即可。
2、 配置文件:redis相关配置文件
2.1 redis.properties
redis.minIdle=5
redis.maxIdle=10
redis.maxTotal=50
redis.maxWaitMillis=1500
redis.testOnBorrow=true
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.minEvictableIdleTimeMillis=1800000
redis.softMinEvictableIdleTimeMillis=10000
redis.testWhileIdle=true
redis.blockWhenExhausted=false
#redis单机版信息
redis.host=182.254.xxx.xx
redis.port=7001
#redis集群版信息
cluster.host1=182.254.xxx.xx
cluster.port1=7001
cluster.host2=182.254.xxx.xx
cluster.port2=7002
cluster.host3=182.254.xxx.xx
cluster.port3=7003
cluster.host4=182.254.xxx.xx
cluster.port4=7004
cluster.host5=182.254.xxx.xx
cluster.port5=7005
cluster.host6=182.254.xxx.xx
cluster.port6=7006
2.2 引入redis.properties
<!-- 引入jdbc、redis等配置文件 -->
<context:property-placeholder location="classpath:*.properties" />
2.3 spring-redis.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- jedis连接池配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最小空闲连接数 -->
<property name="minIdle" value="${redis.minIdle}"/>
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="${redis.maxIdle}"/>
<!-- 最大连接数 -->
<property name="maxTotal" value="${redis.maxTotal}"/>
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/>
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/>
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/>
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="${redis.softMinEvictableIdleTimeMillis}"/>
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="${redis.testWhileIdle}"/>
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="${redis.blockWhenExhausted}"/>
</bean>
<!-- 单机版 -->
<!-- 配置jedis连接池 -->
<bean class="redis.clients.jedis.JedisPool">
<constructor-arg name="poolConfig" ref="poolConfig"/>
<constructor-arg name="host" value="${redis.host}" />
<constructor-arg name="port" value="${redis.port}" />
</bean>
<!-- 配置单机版工具类 -->
<bean class="com.ssm.redis.RedisPool" />
</beans>
两种方案:使用jedis连接池(单机版)和jedis集群,上述配置为单机版
一般生产环境使用集群,开发环境使用单机版
使用哪种,可以将另一种注释掉
注意:如果在注入工具类的时候是按类型注入的话,那么不使用的工具类必须注释掉
集群版如下:
<!-- 集群版 -->
<!-- 配置jedis集群 -->
<bean class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host1}" />
<constructor-arg name="port" value="${cluster.port1}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host2}" />
<constructor-arg name="port" value="${cluster.port2}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host3}" />
<constructor-arg name="port" value="${cluster.port3}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host4}" />
<constructor-arg name="port" value="${cluster.port4}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host5}" />
<constructor-arg name="port" value="${cluster.port5}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host6}" />
<constructor-arg name="port" value="${cluster.port6}" />
</bean>
</set>
</constructor-arg>
</bean>
<!--配置集群版工具类-->
<bean class="com.ssm.redis.RedisCluster" />
3、利用jedis操作redis
3.1 RedisUtil.java:接口类
package com.ssm.redis;
/**
* Redis工具接口
*
*/
public interface RedisUtil {
/**
* 保存
*
* @param key
* 键
* @param value
* zhi
*/
public void set(String key, String value);
/**
* 保存并设置生存时间
*
* @param key
* 键
* @param value
* 值
* @param seconds
* 时间,秒s为单位
*/
public void set(String key, String value, Integer seconds);
/**
* 根据key查询
*
* @param key
* 键
* @return 值
*/
public String get(String key);
/**
* 删除
*
* @param key
* 键
*/
public void del(String key);
/**
* 根据key设置生存时间
*
* @param key
* 键
* @param seconds
* 时间,秒s为单位
*/
public void expire(String key, Integer seconds);
/**
* value加一<br/>
* 注意key必须是整型
*
* @param key
* 键
* @return 加一后的结果
*/
public Long incr(String key);
}
3.2 RedisPool.java:实现RedisUtil接口,单机版
package com.ssm.redis;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* Redis连接池工具类
*/
public class RedisPool implements RedisUtil {
@Autowired
private JedisPool jedisPool;
@Override
public void set(String key, String value) {
Jedis jedis = this.getJedis();
jedis.set(key, value);
this.releaseJedis(jedis);
}
@Override
public void set(String key, String value, Integer seconds) {
Jedis jedis = this.getJedis();
jedis.set(key, value);
jedis.expire(key, seconds);
this.releaseJedis(jedis);
}
@Override
public String get(String key) {
Jedis jedis = this.getJedis();
String result = jedis.get(key);
this.releaseJedis(jedis);
return result;
}
@Override
public void del(String key) {
Jedis jedis = this.getJedis();
jedis.del(key);
this.releaseJedis(jedis);
}
@Override
public void expire(String key, Integer seconds) {
Jedis jedis = this.getJedis();
jedis.expire(key, seconds);
this.releaseJedis(jedis);
}
@Override
public Long incr(String key) {
Jedis jedis = this.getJedis();
Long count = jedis.incr(key);
this.releaseJedis(jedis);
return count;
}
/**
* 获取Jedis连接
*
* @return Jedis连接
*/
private Jedis getJedis() {
return this.jedisPool.getResource();
}
/**
* 释放Jedis连接,返还到连接池
*
* @param jedis
* jedis连接
*/
private void releaseJedis(Jedis jedis) {
jedis.close();
}
}
3.3 RedisCluster.java:实现RedisUtil接口,集群版
package com.ssm.redis;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.JedisCluster;
/**
* Redis集群工具类
*/
public class RedisCluster implements RedisUtil {
@Autowired
private JedisCluster jedisCluster;
@Override
public void set(String key, String value) {
this.jedisCluster.set(key, value);
}
@Override
public void set(String key, String value, Integer seconds) {
this.jedisCluster.set(key, value);
this.jedisCluster.expire(key, seconds);
}
@Override
public String get(String key) {
return this.jedisCluster.get(key);
}
@Override
public void del(String key) {
this.jedisCluster.del(key);
}
@Override
public void expire(String key, Integer seconds) {
this.jedisCluster.expire(key, seconds);
}
@Override
public Long incr(String key) {
return this.jedisCluster.incr(key);
}
/**
* 获取JedisCluster对象
* 可以直接使用它来进行redis操作
*
* @return JedisCluster对象
*/
public JedisCluster getJedisCluster() {
return jedisCluster;
}
}
3、controller层实际测试
@RequestMapping(value = "/guest", method = RequestMethod.GET)
public String guest(Model model,String parameter1) {
LOG.info("进入guest的index");
String key = parameter1;
// 1.从缓存中命中
try {
String redisJson = redisUtil.get(key);
if (StringUtils.isNotBlank(redisJson)) {
LOG.info("从缓存中命中:"+redisJson);
}else{
// 2.如果没被命中,执行原有逻辑
LOG.info("没被命中");
// 此处模拟从数据库获取数据
String json = "getFromDB()";
// 3.将查询出来的结果加入缓存
redisUtil.set(key, json);
redisUtil.expire(key, 60 * 60 * 24);
}
} catch (Exception e) {
e.printStackTrace();
}
return "guest/guestIndex";
}
注意:如果redis没有启动,会在catch块中报 JedisConnectionException: Could not get a resource from the pool
浏览器地址栏输入 :http://127.0.0.1:8080/项目名/guest?parameter1=1,控制台输出:
[ INFO ] 进入guest的index
[ INFO ] 没被命中
浏览器刷新页面,控制台输出:
[ INFO ] 进入guest的index
[ INFO ] 从缓存中命中:getFromDB()
测试成功,在部署redis的系统上登录 redis-cli,利用get命令,也可以查询到该key-value值
4、扩展
4.1 spring+ redis + aop 实现从redis中获取数据
对于某些需求,例如只需要做查询的项目,或者部分数据只做查询,不做增删改的项目(例如省市区表等),可以利用aop与redis,查询数据时先从redis中查询,如果查询不到,则到数据库中查询,然后将数据库中查询的数据放到redis中一份,下次查询时就能直接从redis中查到,不需要查询数据库了。