spring-redis缓存方案学习一:原始template开发

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开发繁琐,对业务入侵强,不推荐使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值