安装
Redis是c语言开发的。
安装redis需要c语言的编译环境。如果没有gcc需要在线安装。yum install gcc-c++
安装步骤:
第一步:redis的源码包上传到linux系统。
第二步:解压缩redis。
第三步:编译。进入redis源码目录。make
第四步:安装。make install PREFIX=/usr/local/redis
PREFIX参数指定redis的安装目录。一般软件安装到/usr目录下
启动
前端启动:在redis的安装目录下直接启动redis-server
[root@localhost bin]# ./redis-server
后台启动:
把解压目录中的/root/redis-3.0.0/redis.conf复制到安装目录中/usr/local/redis/bin目录下
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis/bin/
修改配置文件:
[root@localhost bin]# ./redis-server redis.conf
daemon yes #守护进程改为是
查看redis进程:
[root@localhost bin]# ps aux|grep redis
root 5190 0.1 0.3 33936 1712 ? Ssl 18:23 0:00 ./redis-server *:6379
root 5196 0.0 0.1 4356 728 pts/0 S+ 18:24 0:00 grep redis
关闭
[root@localhost bin]# kill 5190 #正常关闭
[root@localhost bin]# kill -9 5190 #强制关闭
[root@localhost bin]# ./redis-cli shutdown
连接
首先redis.conf文件中设置指定的ip和端口,更改后服务要重启
redis-cli -h 主机 -p 端口
[root@localhost bin]# ./redis-cli -h 192.168.25.3 -p 6379
常用命令
String:key-value(做缓存)
Redis中所有的数据都是字符串。命令不区分大小写,key是区分大小写的。Redis是单线程的。Redis中不适合保存内容大的数据。
get、set、incr:加一(生成id)、Decr:减一
设置键值对: set key value
获取指定键的值: get key
查看所有key: keys *
删除键:del key
指定key的value加一: incr key
指定key的value减一: decr key
Hash :key-fields-values(做缓存)
相当于一个key对于一个map,map中还有key-value。使用hash对key进行归类。
Hset:向hash中添加内容
Hget:从hash中取内容
设置key的fields和values: hset key field value
获取指定key的field的值: hget key field
获取指定key的所有filed字段: hkeys key
获取指定key的所有值: hvals key
删除指定key的指定field字段: hdel key field
获取key的所有fiel和value信息: hgetall key
List:有顺序可重复
从左边添加:lpush key value [value..]
从右边添加:rpush key value [value..]
获取所有list元素: lrange key start end
从左边取出(取出list集合中就不存在了):lpop key
从右边取出(取出list集合中依然不存在): rpop key
Set:元素无顺序,不能重复
在集合中添加元素(自动过滤重复元素): sadd key value[value..]
移除集合中的元素: srem key value[value..]
查看Set中的值:smembers key
第一个set和第二个set做比较: sdiff key1 key2
交集: sinter key1 key2
并集: sunion key1 key2
SortedSet(zset):有顺序,不能重复(消耗性能最高,能用list替代就用list)
按顺序给Set添加元素: zadd zset1 2 a 5 b 1 c 6 d
查看指定key中的所有元素: zrange zset1 0 -1
移除指定key中的指定元素: zrem zset1 a
查询的排序反转: zrange zset1 0 -1
连同排序号一起查出来: zrange zset1 0 -1 withscores
设置key的过期时间
expire key second:设置key的过期时间,一旦过期就清除
ttl key:查看key的有效期
persist key:清除key的过期时间。Key持久化。
持久化方案
Redis的所有数据都是保存到内存中的。
Rdb:快照形式,定期把内存中当前时刻的数据保存到磁盘。Redis默认支持的持久化方案。
aof形式:append only file。把所有对redis数据库操作的命令,增删改操作的命令。保存到文件中。数据库恢复时把所有的命令执行一遍即可。
集群
当redis中的数据是存放在内存中的。当内存存满时会存放在虚拟内存中(虚拟内存效率很低),为了解决这个问题要使用集群,redis每个节点存放的数据是不一样的。
架构细节:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
Redis集群的搭建
Redis集群中至少应该有三个节点。要保证集群的高可用,需要每个节点有一个备份机。
Redis集群至少需要6台服务器。
搭建伪分布式。可以使用一台虚拟机运行6个redis实例。需要修改redis的端口号7001-7006
集群搭建环境
1、使用ruby脚本搭建集群。需要ruby的运行环境。
安装ruby
yum install ruby
yum install rubygems
2、将redis-3.0.0.gem包上传到服务器,安装ruby脚本运行使用的包。
[root@localhost ~]# gem install redis-3.0.0.gem
Successfully installed redis-3.0.0
1 gem installed
Installing ri documentation for redis-3.0.0...
Installing RDoc documentation for redis-3.0.0...
3、从解压包中src下的redis-trib.rb复制到集群目录下
[root@localhost ~]# cd redis-3.0.0/src
[root@localhost src]# ll *.rb
-rwxrwxr-x. 1 root root 48141 Apr 1 2015 redis-trib.rb
[root@localhost src]# cp redis-trib.rb ../../java/redis-cluster/
搭建步骤
需要6台redis服务器。搭建伪分布式。
需要6个redis实例。
需要运行在不同的端口7001-7006
第一步:创建6个redis实例,每个实例运行在不同的端口。需要修改redis.conf配置文件。配置文件中还需要把cluster-enabled yes前的注释去掉。
第二步:启动每个redis实例。
启动redis-cluster文件夹下的六个redis
[root@localhost redis-cluster]# vim start-cluster.sh
cd redis0
./redis-server redis.conf
cd ..
cd redis1
./redis-server redis.conf
cd ..
cd redis2
./redis-server redis.conf
cd ..
cd redis3
./redis-server redis.conf
cd ..
cd redis4
./redis-server redis.conf
cd ..
cd redis5
./redis-server redis.conf
cd ..
[root@localhost redis-cluster]# chmod u+x start-cluster.sh
创建关闭集群的脚本:
[root@localhost redis-cluster]# vi shutdow-all.sh
redis0/redis-cli -p 7000 shutdown
redis1/redis-cli -p 7001 shutdown
redis2/redis-cli -p 7002 shutdown
redis3/redis-cli -p 7003 shutdown
redis4/redis-cli -p 7004 shutdown
redis5/redis-cli -p 7005 shutdown
[root@localhost redis-cluster]# chmod u+x shutdow-all.sh
第三步:使用ruby脚本搭建集群。
./redis-trib.rb create --replicas 1 192.168.25.3:7000 192.168.25.3:7001 192.168.25.3:7002 192.168.25.3:7003 192.168.25.3:7004 192.168.25.3:7005
Jedis
需要把jedis依赖的jar包添加到工程中。Maven工程中需要把jedis的坐标添加到依赖。
连接单机版
第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
第三步:打印结果。
第四步:关闭Jedis。
@Test
public void testJedis() throws Exception {
// 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
Jedis jedis = new Jedis("192.168.25.3", 6379);
// 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
String result = jedis.get("hello");
// 第三步:打印结果。
System.out.println(result);
// 第四步:关闭Jedis
jedis.close();
}
连接单机版使用连接池
第一步:创建一个JedisPool对象。需要指定服务端的ip及端口。
第二步:从JedisPool中获得Jedis对象。
第三步:使用Jedis操作redis服务器。
第四步:操作完毕后关闭jedis对象,连接池回收资源。
第五步:关闭JedisPool对象。
@Test
public void testJedisPool() throws Exception {
// 第一步:创建一个JedisPool对象。需要指定服务端的ip及端口。
JedisPool jedisPool = new JedisPool("192.168.25.153", 6379);
// 第二步:从JedisPool中获得Jedis对象。
Jedis jedis = jedisPool.getResource();
// 第三步:使用Jedis操作redis服务器。
jedis.set("jedis", "test");
String result = jedis.get("jedis");
System.out.println(result);
// 第四步:操作完毕后关闭jedis对象,连接池回收资源。
jedis.close();
// 第五步:关闭JedisPool对象。
jedisPool.close();
}
连接集群
第一步:使用JedisCluster对象。需要一个Set<HostAndPort>参数。Redis节点的列表。
第二步:直接使用JedisCluster对象操作redis。在系统中单例存在。
第三步:打印结果
第四步:系统关闭前,关闭JedisCluster对象。
@Test
public void testJedisCluster() throws Exception {
// 第一步:使用JedisCluster对象。需要一个Set<HostAndPort>参数。Redis节点的列表。
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.25.153", 7001));
nodes.add(new HostAndPort("192.168.25.153", 7002));
nodes.add(new HostAndPort("192.168.25.153", 7003));
nodes.add(new HostAndPort("192.168.25.153", 7004));
nodes.add(new HostAndPort("192.168.25.153", 7005));
nodes.add(new HostAndPort("192.168.25.153", 7006));
JedisCluster jedisCluster = new JedisCluster(nodes);
// 第二步:直接使用JedisCluster对象操作redis。在系统中单例存在。
jedisCluster.set("hello", "100");
String result = jedisCluster.get("hello");
// 第三步:打印结果
System.out.println(result);
// 第四步:系统关闭前,关闭JedisCluster对象。
jedisCluster.close();
}
向业务逻辑中添加缓存
接口封装
常用的操作redis的方法提取出一个接口,分别对应单机版和集群版创建两个实现类。
/*接口定义*/
public interface JedisClient {
String set(String key, String value);
String get(String key);
Boolean exists(String key);
Long expire(String key, int seconds);
Long ttl(String key);
Long incr(String key);
Long hset(String key, String field, String value);
String hget(String key, String field);
Long hdel(String key, String... field);
}
/*单机版实现类*/
public class JedisClientPool implements JedisClient {
@Autowired
private JedisPool jedisPool;
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
}
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}
@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.exists(key);
jedis.close();
return result;
}
@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, seconds);
jedis.close();
return result;
}
@Override
public Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public Long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}
@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, field);
jedis.close();
return result;
}
@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}
}
<!-- 配置单机版的连接 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.25.3"></constructor-arg>
<constructor-arg name="port" value="6379"></constructor-arg>
</bean>
<bean class="com.e3mall.common.jedis.JedisClientPool">
<property name="jedisPool" ref="jedisPool"></property>
</bean>
/*集群版实现类*/
package cn.e3mall.jedis;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.JedisCluster;
public class JedisClientCluster implements JedisClient {
@Autowired
private JedisCluster jedisCluster;
@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public Boolean exists(String key) {
return jedisCluster.exists(key);
}
@Override
public Long expire(String key, int seconds) {
return jedisCluster.expire(key, seconds);
}
@Override
public Long ttl(String key) {
return jedisCluster.ttl(key);
}
@Override
public Long incr(String key) {
return jedisCluster.incr(key);
}
@Override
public Long hset(String key, String field, String value) {
return jedisCluster.hset(key, field, value);
}
@Override
public String hget(String key, String field) {
return jedisCluster.hget(key, field);
}
@Override
public Long hdel(String key, String... field) {
return jedisCluster.hdel(key, field);
}
}
<!-- 集群版的配置 -->
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg>
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.3"></constructor-arg>
<constructor-arg name="port" value="7001"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.3"></constructor-arg>
<constructor-arg name="port" value="7002"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.3"></constructor-arg>
<constructor-arg name="port" value="7003"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.3"></constructor-arg>
<constructor-arg name="port" value="7004"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.3"></constructor-arg>
<constructor-arg name="port" value="7005"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.3"></constructor-arg>
<constructor-arg name="port" value="7006"></constructor-arg>
</bean>
</set>
</constructor-arg>
</bean>
<bean id="jedisClientCluster" class="com.e3mall.common.jedis.JedisClientCluster">
<property name="jedisCluster" ref="jedisCluster"></property>
</bean>
注意:单机版和集群版不能共存,使用单机版时注释集群版的配置。使用集群版,把单机版注释。
封装代码测试
@Test
public void testJedisClient() throws Exception {
//初始化Spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-redis.xml");
//从容器中获得JedisClient对象
JedisClient jedisClient = applicationContext.getBean(JedisClient.class);
jedisClient.set("first", "100");
String result = jedisClient.get("first");
System.out.println(result);
}
添加缓存
功能分析
查询内容列表时添加缓存。
1、查询数据库之前先查询缓存。
2、查询到结果,直接响应结果。
3、查询不到,缓存中没有需要查询数据库。
4、把查询结果添加到缓存中。
5、返回结果。
向redis中添加缓存:
Key:cid
Value:内容列表。需要把java对象转换成json。
使用hash对key进行归类。
HASH_KEY:HASH
|--KEY:VALUE
|--KEY:VALUE
|--KEY:VALUE
|--KEY:VALUE
注意:添加缓存不能影响正常业务逻辑。
String key = this.getClass().getName() +"."+ Thread.currentThread().getStackTrace()[1].getMethodName(); //包名.类名.方法名
String field = "sys_information_type:"+sys_information_type+",id:"+id; //方法参数
if (jedisClient.hget(key, field)!=null) { //判断redis中是否存在
System.out.println("从redis中取");
//向客户端输出
resp.reset();
resp.setContentType("text/plain; charset=UTF-8");
resp.setCharacterEncoding("utf-8");
resp.getOutputStream().write(jedisClient.hget(key, field).getBytes("utf-8"));
resp.getOutputStream().flush();
return null;
}
//将数据库中查找的数据转换为json格式存储到redis中
JSONObject jsonObject=new JSONObject();
从数据库中查找数据...
//将查询到的数据存储在redis中
jedisClient.hset(key, field, jsonObject.toString());
jedisClient.expire(key, 60); //经常更新的数据可以设置过期时间,单位秒
返回数据...
缓存同步
对内容信息做增删改操作后只需要把对应缓存删除即可。不用把整个hash删掉,删掉hash指定的field即可。
jedisClient.expire(key, 0); //将指定key设过期,string,hash都可以
--------------------------------20180725分割线--------------------
spring+jackson环境
封装类RedisTool.java类
public class RedisTool {
@Autowired
JedisClient jedisClient;
public JedisClient getJedisClient() {
return jedisClient;
}
public void setJedisClient(JedisClient jedisClient) {
this.jedisClient = jedisClient;
}
public RedisTool() {
}
/**
* 查询是否存在
* @Pa
* @param paramString 参数拼接成的字符串
* @return 存在返回json字符串,不存在返回none
* @throws UnsupportedEncodingException
*/
public String getReids(String key,String paramString){
//String key = this.getClass().getName() +"."+ Thread.currentThread().getStackTrace()[1].getMethodName(); //包名.类名.方法名
String field = paramString; //方法参数
if (jedisClient.hget(key, field)!=null) { //判断redis中是否存在
String result = jedisClient.hget(key, field);
System.out.println("从redis中取"+result);
//向客户端输出
return result;
}
return "none";
}
/**
* 向redis中添加
* @param paramString 参数拼接成的字符串
* @param jsonObject 结果- 缓存到redis中的字符串
* @throws UnsupportedEncodingException
*/
public void setReids(String key,String paramString,String jsonObject) throws UnsupportedEncodingException {
String field = paramString;
//String key = this.getClass().getName() +"."+ Thread.currentThread().getStackTrace()[1].getMethodName(); //包名.类名.方法名
jedisClient.hset(key, field, jsonObject);
jedisClient.expire(key, 60); //经常更新的数据可以设置过期时间,单位秒
}
}
Controller层
@RequestMapping("/getAllBook")
@ResponseBody
public Page getAllBook(String pageNo,String pageSize,String cateCode_search,String money_search_start,String money_search_end,String time_search_start,String time_search_end,String remark_search,HttpServletRequest request,HttpServletResponse response) throws IOException {
pageNo=pageNo==null?"1":pageNo; //当前页码
pageSize=pageSize==null?"5":pageSize; //页面大小
/*从redis中读取*/
//key参数
String redis_key = this.getClass().getName() +"."+ Thread.currentThread().getStackTrace()[1].getMethodName(); //包名.类名.方法名
String userId = ((Users)request.getSession().getAttribute("user")).getId().toString();
//field参数
String paramString = "userId"+userId+"pageNo:"+pageNo+"pageSize"+pageSize+"cateCode_search"+cateCode_search+"money_search_start"+money_search_start+"money_search_end"+money_search_end+"time_search_start"+time_search_start+"time_search_end"+time_search_end+"remark_search"+remark_search;
if(redisTool.getReids(redis_key,paramString)!="none"){ //读取
Page page = null;
try {
page = new ObjectMapper().readValue(redisTool.getReids(redis_key,paramString),Page.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return page;
}
//
//获取当前页数据
List<AccountExt> list = bookService.getAllBookByPage(userId,cateCode_search,money_search_start,money_search_end,time_search_start,time_search_end,remark_search,pageNo,pageSize);
//获取总数据大小
int totals = bookService.getAllBookCount(userId,cateCode_search,money_search_start,money_search_end,time_search_start,time_search_end,remark_search);
//封装返回结果
Page page = new Page();
page.setTotal(totals+"");
page.setRows(list);
/*存入redis中*/
String jsonResult = new ObjectMapper().writeValueAsString(page);
redisTool.setReids(redis_key,paramString,jsonResult);
return page;
}
applicationContext-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<bean class="org.apache.commons.pool2.impl.GenericObjectPoolConfig" id="poolConfig">
</bean>
<!--redis配置-->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
<constructor-arg name="host" value="www.52zt.online"></constructor-arg>
<constructor-arg name="port" value="6379"></constructor-arg>
<constructor-arg name="timeout" value="5000"></constructor-arg>
<constructor-arg name="password" value="19950926"></constructor-arg>
</bean>
<bean class="com.autumn.redis.JedisClientPool" id="jedisClientPool">
<property name="jedisPool" ref="jedisPool"></property>
</bean>
<bean class="com.autumn.redis.RedisTool">
<property name="jedisClient" ref="jedisClientPool"></property>
</bean>
</beans>
web.xml
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
来源:oschina
链接:https://my.oschina.net/u/4347493/blog/4124188