1.通过maven导入redis开发相关jar包
<!-- redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- spring对redis的支持 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.4.RELEASE</version>
</dependency>
2:编写redis.properties文件
#redis的服务器地址
redis.host=192.168.1.183
#redis的服务端口
redis.port=6379
#密码
redis.pass=root
#链接数据库
redis.default.db=0
#客户端超时时间单位是毫秒
redis.timeout=100000
#最大连接数
redis.maxTotal=300
#最大空闲数
redis.maxIdle=100
#最大建立连接等待时间
redis.maxWaitMillis=1000
#指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
redis.testOnBorrow=true
3:在spring的spring-Mybatis.xml中配置redis连接池和调用模板
<!-- 2.引入配置文件(传统方式) -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- 这里支持多种寻址方式:classpath和file -->
<value>classpath:jdbc.properties</value>
<value>classpath:redis.properties</value>
<!-- 推荐使用file的方式引入,这样可以将配置和代码分离 -->
</list>
</property>
</bean>
<!-- 配置reids连接池 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxTotal}" />
<property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- 配置redis连接池工厂 -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
destroy-method="destroy">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="database" value="${redis.default.db}" />
<property name="timeout" value="${redis.timeout}" />
<property name="usePool" value="true" />
<property name="poolConfig" ref="poolConfig" />
</bean>
<!-- key序列化策略 -->
<bean id="keySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
<!-- value序列化策略 -->
<bean id="valueSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
<!-- spring-redis模板 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="keySerializer" ref="keySerializer" />
<property name="valueSerializer" ref="valueSerializer" />
<!-- 配置redis是否支持事务 -->
<property name="enableTransactionSupport" value="true" />
</bean>
注意,放进缓存里的对象要序列化,不然会抛出异常
RedisTemplate和 Serializer详解
可以看到我在代码中注释掉了一段代码,现在可以解释上面留下的两个问题了,第一个是在redis.xml中配置redistemplate的时候,同时配置了两个Serializer:keySerializer实现了StringRedisSerializer,valueSerializer实现了JdkSerializationRedisSerializer。
一、为什么要使用Serializer
因为redis是以key-value的形式将数据存在内存中,key就是简单的string,key似乎没有长度限制,不过原则上应该尽可能的短小且可读性强,无论是否基于持久存储,key在服务的整个生命周期中都会在内存中,因此减小key的尺寸可以有效的节约内存,同时也能优化key检索的效率。
value在redis中,存储层面仍然基于string,在逻辑层面,可以是string/set/list/map,不过redis为了性能考虑,使用不同的“encoding”数据结构类型来表示它们。(例如:linkedlist,ziplist等)。
所以可以理解为,其实redis在存储数据时,都把数据转化成了byte[]数组的形式,那么在存取数据时,需要将数据格式进行转化,那么就要用到序列化和反序列化了,这也就是为什么需要配置Serializer的原因。
二、SDR支持的序列化策略:
(详细可查阅API文档)
JdkSerializationRedisSerializer:
StringRedisSerializer:
JacksonJsonRedisSerializer:
OxmSerializer:
其中JdkSerializationRedisSerializer和StringRedisSerializer是最基础的序列化策略,其中“JacksonJsonRedisSerializer”与“OxmSerializer”都是基于stirng存储,因此它们是较为“高级”的序列化(最终还是使用string解析以及构建java对象)。
基本推荐使用JdkSerializationRedisSerializer和StringRedisSerializer,因为其他两个序列化策略使用起来配置很麻烦,如果实在有需要序列化成Json和XML格式,可以使用java代码将String转化成相应的Json和XML。
4.编写redis工具类
@Component
public class RedisUtil {
@Autowired
RedisTemplate<String, Object> template;
/**
* 向redis添加一个键值
* @param key
* @return
*/
public Object getDataFromCache(String key){
BoundValueOperations<String, Object> bound = template.boundValueOps(key);
return bound.get();
}
/**
* 从redis中取出一个键值
* @param key
* @param data
*/
public void setDataToCache(String key,Object data){
BoundValueOperations<String,Object> ops = template.boundValueOps(key);
ops.set(data);
}
/**
* 清除缓存
* @param cacheKey
*/
public void clearCache(String cacheKey){
template.delete(cacheKey);
}
/**
* 从缓存中获取一个list
* @param cacheKey
* @return
*/
public List<Object> getCacheList(String cacheKey){
BoundListOperations<String, Object> bound = template.boundListOps(cacheKey);
long size = bound.size();
return bound.range(0, size);
}
/**
* 覆盖一个list
* @param cacheKey
* @param dataList
*/
public void updatCacheList(String cacheKey,List<Object> dataList){
template.delete(cacheKey);
BoundListOperations<String, Object> bound = template.boundListOps(cacheKey);
bound.rightPushAll(dataList.toArray());
}
/**
* 获取一个hash
* @param cacheKey
* @return
*/
public Map<String, Object> getCacheMap(String cacheKey){
BoundHashOperations<String, String, Object> bound = template.boundHashOps(cacheKey);
return bound.entries();
}
/**
* 从hash里获取一个值
* @param cacheKey
* @param key
* @return
*/
public Object getDataFromCacheMap(String cacheKey,Object key){
BoundHashOperations<String, Object, Object> bound = template.boundHashOps(cacheKey);
return bound.get(key);
}
/**
* 向hash放进一个键值
* @param cacheKey
* @param key
* @param value
*/
public void setDataFromCacheMap(String cacheKey,Object key,Object value){
BoundHashOperations<String, Object, Object> bound = template.boundHashOps(cacheKey);
bound.put(key, value);
}
}
5.编写缓存服务类
创建一个缓存服务接口
/**
* cache接口
* @author yuli
*
*/
public interface CacheService {
/**
* 获取缓存
* @param key
* @return
*/
public <T> T cacheResult(String key);
/**
* 移除缓存
* @param key
*/
public void cacheRemove(String key);
/**
* 从缓存中获取值
* @param key
* @param value
*/
public <T> void cachePut(String key,T value);
}
实现接口
/**
* 缓存接口redis实现类
* @author yuli
*
*/
@Service
public class CacheServiceImpl implements CacheService {
@Autowired
private RedisUtil redisUtil;
/**
* 获取数据
*/
@SuppressWarnings("unchecked")
public <T> T cacheResult(String key) {
return (T) redisUtil.getDataFromCache(key);
}
/**
* 清除缓存
*/
public void cacheRemove(String key) {
redisUtil.clearCache(key);
}
/**
* 放入缓存
*/
public <T> void cachePut(String key, T value) {
redisUtil.setDataToCache(key, value);
}
}
6.在业务层加入缓存
@Service
public class UserServiceImpl implements UserService {
public static Logger logger = Logger.getLogger(UserServiceImpl.class);
@Autowired
private UserMapper userMpper;//usermapper接口
@Autowired
private CacheService cs;//缓存实现
@Transactional
public User addUser(User user) {
userMpper.insert(user);
logger.info("向数据库添加用户");
//添加缓存
cs.cachePut(user.getId(), user);
return user;
}
@Transactional
public void deleteUser(String userId) {
userMpper.deleteByPrimaryKey(userId);
//移除缓存
cs.cacheRemove(userId);
}
@Transactional
public User updateUser(User user) {
userMpper.updateByPrimaryKeySelective(user);
//覆盖缓存
cs.cachePut(user.getId(), user);
return user;
}
@Transactional(readOnly=true)
public User queryUser(String userId) {
User rUser = cs.cacheResult(userId);
//判断缓存是否存在,存在就返回redis里的user
if(rUser != null){
logger.info("从缓存里取得数据");
return rUser;
}
//不存在就查询数据库并将user放进缓存里
logger.info("从数据库里取得用户");
User user = userMpper.selectByPrimaryKey(userId);
cs.cachePut(userId, user);
return user;
}
原始template开发繁琐,对业务入侵强,不推荐使用。