Spring集成Redis步骤
2017-04-22 09:25
701 查看
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缓存可以显著提高性能。
相关文章推荐
- spring和redis整合集成步骤
- 基于哨兵【sentinel】模式的redis服务集群并与spring集成
- SpringBoot集成Redis来实现缓存技术方案
- spring集成 JedisCluster 连接 redis3.0 集群
- Spring集成Redis详解代码示例
- Spring Boot集成Redis实现缓存
- 分布式缓存技术redis学习系列(五)——spring-data-redis与JedisPool的区别、使用ShardedJedisPool与spring集成的实现及一致性哈希分析
- redis 学习笔记(5)-Spring与Jedis的集成
- spring-data-redis,jedis和redis主从集成和遇到的问题
- Redis与spring的集成
- Spring-Boot 集成Solr客户端的详细步骤
- 四:redis主从读写分离,哨兵模式与spring的集成
- spring boot 自学笔记(三) Redis集成—RedisTemplate
- spring集成redis的lettuce连接pom文件配置
- redis与spring的集成
- Redis 缓存 + Spring 的集成示例
- Redis-3.0.6 集群部署集成SpringJava工程-----环境搭建
- SpringBoot利用redis集成消息队列的方法
- redis部署安装,以及spring 集成
- 集成spring-data-jpa和spring-data-redis