Spring集成Redis步骤

redis简介

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

本文介绍在Spring中使用Jedis做缓存,将部分db中的数据缓存在redis中,优先从redis中获取,以提高性能。

Spring集成

1、pom.xml引入相关jar包

 <!--spring redis-->
 <dependency>
       <groupId>org.springframework.data</groupId>
       <artifactId>spring-data-redis</artifactId>
       <exclusions>
           <exclusion>
               <groupId>org.springframework</groupId>
               <artifactId>spring-aop</artifactId>
           </exclusion>
       </exclusions>
       <version>1.7.1.RELEASE</version>
   </dependency>
   <dependency>
       <groupId>redis.clients</groupId>
       <artifactId>jedis</artifactId>
       <version>2.8.1</version>
   </dependency>

2、redis链接配置参数

配置在setting.properties文件中,在spring.xml中通过<context:property-placeholder location="classpath:setting.properties"/>引入。

##redis连接配置
redis.host=127.0.0.1
redis.port=6379
redis.pass=admineap
redis.database=0
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true
#当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
redis.timeout=10000

3、spring-redis.xml配置

这部分配置了redis的基本配置

<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-4.0.xsd">

  <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}"/>
       <!-- <property name="maxActive" value="${redis.maxActive}"/>
        <property name="maxWait" value="${redis.maxWait}"/>-->
        <property name="maxWaitMillis" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
    </bean>

    <bean id="connectionFactory" 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.pass}"/>
        <property name="database" value="${redis.database}"/>
        <property name="timeout" value="${redis.timeout}"/>
        <property name="poolConfig" ref="poolConfig"/>
    </bean>


    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory"   ref="connectionFactory" />
    </bean>
</beans>

4、redis通用操作(redisDao与redisDaoImpl)

  • redisDao接口实现代码
package com.cnpc.framework.base.dao;


import java.util.List;
import java.util.Set;

/**
 * Created by billJiang on 2017/4/10.
 * e-mail:475572229@qq.com  qq:475572229
 */
public interface RedisDao {
    <T> boolean add(final String key, final T obj);

    /**
     * setNx
     *
     * @param key
     * @param value
     * @return
     */
    boolean add(final String key, final String value);

    <T> boolean add(final String key, final List<T> list);

    void delete(final String key);

    void delete(final List<String> keys);

    <T> boolean update(final String key, final T obj);

    boolean update(final String key, final String value);

    /**
     * 保存 不存在则新建,存在则更新
     *
     * @param key
     * @param value
     * @return
     */
    boolean save(final String key, final String value);

    <T> boolean save(final String key, final T obj);

    <T> T get(final String key, final Class clazz);

    <T> List<T> getList(final String key, final Class<T> clazz);

    byte[] getByte(final String key);

    String get(final String key);

    <T> void add(final String key, final long timeout, final T obj);

    void add(final String key, final long timeout, final byte[] object);

    Set<String> keys(String pattern);

    boolean exist(final String key);

    boolean set(final String key,final byte[] value);

    boolean flushDB();

    long dbSize();
}
  • redisDaoImpl的代码
package com.cnpc.framework.base.dao.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.BooleanCodec;
import com.cnpc.framework.base.dao.RedisDao;
import com.cnpc.framework.utils.StrUtil;
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.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Created by billJiang on 2017/4/10.
 * e-mail:475572229@qq.com  qq:475572229
 * redis操作实体类
 */
@Service("redisDao")
public class RedisDaoImpl implements RedisDao {

    @Resource
    protected RedisTemplate<String, Serializable> redisTemplate;

    /**
     * 设置redisTemplate
     *
     * @param redisTemplate the redisTemplate to set
     */
    public void setRedisTemplate(RedisTemplate<String, Serializable> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public RedisTemplate<String, Serializable> getRedisTemplate() {
        return redisTemplate;
    }

    /**
     * 获取 RedisSerializer
     */
    private RedisSerializer<String> getRedisSerializer() {
        return redisTemplate.getStringSerializer();
    }


    @Override
    public <T> boolean add(final String key, final T obj) {
        return add(key, JSON.toJSONString(obj));
    }

    @Override
    public <T> void add(final String key, final long timeout, final T obj) {
        redisTemplate.execute(new RedisCallback() {
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                final byte[] object = serializer.serialize(JSON.toJSONString(obj));
                add(key,timeout,object);
                return null;
            }


        });
    }


    @Override
    public void add(final String key, final long timeout,final byte[] object) {
        redisTemplate.execute(new RedisCallback() {
            public Object doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                connection.setEx(keyStr, timeout, object);
                return null;
            }
        });
    }


    @Override
    public boolean add(final String key, final String value) {
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                byte[] object = serializer.serialize(value);
                return connection.setNX(keyStr, object);
            }
        });
        return result;
    }

    @Override
    public <T> boolean add(final String key, final List<T> list) {
        return this.add(key, JSON.toJSONString(list));
    }


    @Override
    public void delete(final String key) {
        List<String> list = new ArrayList<>();
        list.add(key);
        this.delete(list);
    }

    @Override
    public void delete(final List<String> keys) {
        redisTemplate.delete(keys);
    }

    @Override
    public <T> boolean update(final String key, final T obj) {
        return this.update(key, JSON.toJSONString(obj));
    }


    @Override
    public boolean update(final String key, final String value) {
        if (get(key) == null) {
            throw new NullPointerException("数据行不存在, key = " + key);
        }
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                byte[] valueStr = serializer.serialize(value);
                connection.set(keyStr, valueStr);
                return true;
            }
        });
        return result;
    }

    @Override
    public boolean save(String key, String value) {
        if (StrUtil.isEmpty(get(key))) {
            return this.add(key, value);
        } else {
            return this.update(key, value);
        }
    }

    @Override
    public <T> boolean save(String key, T obj) {
        if (get(key, obj.getClass()) == null) {
            return this.add(key, obj);
        } else {
            return this.update(key, obj);
        }
    }

    @Override
    public <T> T get(final String key, final Class clazz) {
        T result = redisTemplate.execute(new RedisCallback<T>() {
            public T doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                byte[] value = connection.get(keyStr);
                if (value == null) {
                    return null;
                }
                String valueStr = serializer.deserialize(value);
                return (T) JSON.parseObject(valueStr, clazz);
            }
        });
        return result;
    }


    @Override
    public <T> List<T> getList(final String key, final Class<T> clazz) {
        List<T> result = redisTemplate.execute(new RedisCallback<List<T>>() {
            public List<T> doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                byte[] value = connection.get(keyStr);
                if (value == null) {
                    return null;
                }
                String valueStr = serializer.deserialize(value);
                return JSON.parseArray(valueStr, clazz);
            }
        });
        return result;
    }



    @Override
    public String get(final String key) {
        String result = redisTemplate.execute(new RedisCallback<String>() {
            public String doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                byte[] value = connection.get(keyStr);
                if (value == null) {
                    return null;
                }
                String valueStr = serializer.deserialize(value);
                return valueStr;
            }
        });
        return result;
    }

    @Override
    public byte[] getByte(final String key) {
        byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
            public byte[] doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                byte[] value = connection.get(keyStr);
                return value;
            }
        });
        return result;
    }

    @Override
    public Set<String> keys(final String pattern) {
        return redisTemplate.keys(pattern);
    }

    @Override
    public boolean exist(final String key){
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                return connection.exists(keyStr);
            }
        });
        return result;
    }


    @Override
    public boolean set(final String key,final byte[] value){
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection)
                    throws DataAccessException {
                RedisSerializer<String> serializer = getRedisSerializer();
                byte[] keyStr = serializer.serialize(key);
                connection.set(keyStr, value);
                return true;
            }
        });
        return result;
    }

    public boolean flushDB(){
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection)
                    throws DataAccessException {
                connection.flushDb();
                return true;
            }
        });
        return result;
    }

    public long dbSize(){
        long result = redisTemplate.execute(new RedisCallback<Long>() {
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.dbSize();
            }
        });
        return result;
    }

}

使用实例

这里写图片描述

比如,在如下场景中,我的文件夹每个栏目右侧显示的是当前类目的数量,可以将这些数据存放在redis缓存中,只要缓存中存在就从缓存中取,否则从数据库中读取。

在相关业务导致数据变化的时候,则可强制缓存失效(设置缓存过期或删除缓存),则下次再读取数据的时候因为缓存无法命中而会从数据库中读取,从而拿到最新的数据。

相关代码

  @Override
    public Map getMessageCount() {
        //优先从redis中读取,不存在,则从数据库中读取,因为本数据与个人用户相关,缓存名加上用户标识
        Map<String, Integer> retMap =redisDao.get(RedisConstant.MESSAGE_PRE+"count:"+SecurityUtil.getUserId(),Map.class);
        if(retMap==null) {
            retMap = new HashMap<>();
            //发件箱
            String hql_sent = "select count(id) from Message where sendUserID='" + SecurityUtil.getUserId() + "'";
            Long count_sent = this.get(hql_sent);
            retMap.put("sent", count_sent.intValue());
            //草稿箱
            String hql_draft = "select count(id) from Message where sendUserID='" + SecurityUtil.getUserId() + "' and messageStatus='0'";
            Long count_draft = this.get(hql_draft);
            retMap.put("draft", count_draft.intValue());
            //收件箱
            String hql_inbox = "select count(id) from MessageReceiver where receiveUserID='" + SecurityUtil.getUserId() + "' and deleted=0";
            Long count_inbox = this.get(hql_inbox);
            retMap.put("inbox", count_inbox.intValue());
            //回收站
            String hql_trash = "select count(id) from MessageReceiver where receiveUserID='" + SecurityUtil.getUserId() + "' and deleted=1 ";
            Long count_trash = this.get(hql_trash);
            retMap.put("trash", count_trash.intValue());
            //将结果存入缓存
            redisDao.add(RedisConstant.MESSAGE_PRE+"count:"+SecurityUtil.getUserId(), retMap);
            return retMap;
        }else {
            return retMap;
        }
    }

 @Override
    public void deleteCacheForMsgCount(){
        redisDao.delete(RedisConstant.MESSAGE_PRE+"count:"+SecurityUtil.getUserId());
    }


数据变化将缓存删除或设置为过期

    @RequestMapping(value = "/save")
    @ResponseBody
    public Result save(String message) {
        Message msgobj = JSON.parseObject(message, Message.class);
        //保存为草稿或保存并直接发送
        messageService.deleteCacheForMsgCount();
        return messageService.saveMessage(msgobj);
    }


    @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
    @ResponseBody
    public Result delete(@PathVariable("id") String id) {
        Message message = this.get(id);
        if (!MessageConstant.SEND_STATUS_DRAFT.equals(message.getMessageStatus())) {
            return new Result(false, "该消息不是草稿状态,不能删除");
        }
        try {
            messageService.delete(message);
            messageService.deleteCacheForMsgCount();
            return new Result();
        } catch (Exception e) {
            return new Result(false, "该数据已经被引用,不可删除");
        }
    }

使用缓存后,性能对比
下面对比了请求,上面是通过redis缓存读取,下面是通过数据库读取,两次用时差别很多,说明使用redis缓存可以显著提高性能。

这里写图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值