redis的概念
redis由C语言开发,基于内存的数据库,数据的存储方式是以KET-VALUE的形式存储,redis中也是有丰富的数据类型的。
2. redis的特点
- redis将数据存储到内存当中,所有读写的效率非常的高:读可以达到:11w/s ,写可一个达到:8w/s。
- redis中也有丰富的数据类型:五种,String、List、Set、Hash、sortedSet。
- redis可以很方便的将数据移植到另一台装有redis的服务器中。因为redis中有且只有一个文件专门来粗放数据,直接把文件复制过去就可以了。
- redis中的所有操作都是原子性的,保证了 数据的完整性。
3. redis的数据类型特点和使用范围
string: 字符串
特点: 和 java中 String 是类似的, 指代的是字符串
使用范围: 做缓存
hash :
特点: 和 java中 hashMap是类似的, 可以很方便的保存对象
使用范围: 做缓存(这种数据类型使用较少,可以被string所替代)
list :
特点: 和 java 中 linkedList是类似的, 看做是一个队列(FIFO)
使用范围: 做任务队列
set:
特点: 和 java中 set集合类似的, 无序 不重复
使用范围: 去重业务
sortedSet
特点: 和 java 中 sortedSet集合类似的 有序的, 不重复的’
使用范围: 做排序(排行榜)
4. redis的安装
建议大家将其安装到一 台没有mysql的虚拟机当中, 如果三台都安装了mysql, 随意的找一台安装redis即可
4.1 安装目录的准备:
安装目录: /export/servers
软件存放的目录: /export/software
日志文件的目录: /export/logs
数据存放的目录: /export/data
创建以上目录:
mkdir -p /export/servers
mkdir -p /export/software
mkdir -p /export/logs
mkdir -p /export/data
4.2 下载redis安装包
cd /export/software/
wget http://download.redis.io/releases/redis-4.0.2.tar.gz
tar -zxvf redis-4.0.2.tar.gz -C ../servers
cd /export/servers/
mv redis-4.0.2 redis-src
4.3 安装编译环境
由于下载下来的只是redis的源码包, 需要对其进行编译执行, 故需要安装C语言环境
yum -y install gcc gcc-c++ libstdc++-devel tcl -y
4.4 编译并进行安装redis
cd /export/servers/redis-src/
make MALLOC=libc
make PREFIX=/export/servers/redis install
4.5 准备redis的启动的相关配置文件
在指定的位置创建一个redis的配置文件
mkdir -p /export/servers/redis/conf
cd /export/servers/redis/conf
vi redis_6379.conf
配置文件的内容如下
注意:
-
内容中的bind 后面的ip地址需要配置成自己虚拟机的ip地址, 将以下的内容复制好以后, :wq退出即可
-
在进行复制之前先输入 i 进行编辑模式
bind 192.168.72.144
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize yes
supervised no
pidfile /export/data/redis/6379/redis_6379.pid
loglevel notice
logfile “/export/data/redis/6379/log.log”
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /export/data/redis/6379/
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no
appendonly yes
appendfilename “appendonly.aof”
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble no
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events “”
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
4.6 启动redis的服务
mkdir -p /export/data/redis/6379/
cd /export/servers/redis/bin/
./redis-server ../conf/redis_6379.conf
查看是否正常启动redis的服务
查看是否正确启动的命令
ps -ef|grep redis
redis和mysql一样也是分为服务端和客户端, 刚刚我们已经启动了redis的服务端, 接下来就可以使用客户端连接redis了
redis的客户端的连接
使用: -h 跟着redis的服务器的ip地址
cd /export/servers/redis/bin/
./redis-cli -h 192.168.72.144
以下命令为检测命令:
输入: ping 返回 pong 表示成功
客户端退出:
第一种:强制退出 Ctrl+c
第二种: quit
- jedis客户端工具
5.1 什么是jedis
jedis的是一款用于redis的数据库的Java客户端工具, jedis提供了一套非常省力的API, 其最大的特点就是其API和redis的命令是相同的, 这样就大大降低了学习的成本, 其本身也是redis官方推荐的一款javaAPI
5.2 jedis的入门
- 导入相关jedis的包
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
/**
* jedis的入门代码
*/
@Test
public void jedisOne() {
//1. 创建jedis对象
Jedis jedis = new Jedis("192.168.72.144",6379);
//2. 测试是否连通
String pong = jedis.ping();
//返回PONG 表示已经连通
System.out.println(pong);
//3. 释放资源
jedis.close();
}
5.3 jedis的常用API
4.3.1 使用jedis操作redis–>String
/**
* jedis操作redis--> String
*
* String类型的应用场景:
* 做缓存
* @throws InterruptedException
*/
@Test
public void jedisOfString() throws InterruptedException {
//1. 创建jedis的对象
Jedis jedis = new Jedis("192.168.72.144", 6379);
//2. 执行相关操作:
//2.1 向redis中存值
jedis.set("age", "19");
//2.2 向redis中获取值
String age = jedis.get("age");
System.out.println(age);
//2.3 删除值
//jedis.del("age");
//2.4 为age进行+1操作
Long incr = jedis.incr(age);
System.out.println(incr);
//2.5 为age进行-1操作
Long decr = jedis.decr("age");
System.out.println(decr);
//2.6 拼接字符串: 如果key存在就是拼接, 如果不存在就会重新创建
jedis.append("hobby", "篮球");
String hobby = jedis.get("hobby");
System.out.println(hobby);
//2.7 为key 设置有效时长
//为已有的key设置有效时间
Long expire = jedis.expire("hobby", 5);
System.out.println(expire);//返回1 表示设置成功, 返回0 表示该key不存在
while(jedis.exists("hobby")) {
System.out.println(jedis.ttl("hobby"));//返回-1 表示永久有效, -2 key不存在
Thread.sleep(1000);
}
//为新建的key设置有效时间
jedis.setex("date", 10, "2018.9.15");
while(jedis.exists("date")) {
System.out.println(jedis.ttl("date"));
Thread.sleep(1000);
}
//3. 释放资源
jedis.close();
}
4.3.2 使用jedis操作redis–>list
/**
* 使用jedis操作redis --> list
*
* list可以将其看做是java的队列类似
*
* list数据类型的应用场景: 任务队列
*/
@Test
public void jedisOfList() {
//1. 创建jedis对象
Jedis jedis = new Jedis("192.168.72.144",6379);
//执行操作前删清空集合中的数据,否则会一直往里面添加
jedis.del("list1");
jedis.del("list2");
//2. 执行list相关的操作
//2.1 添加数据: 从左侧添加
jedis.lpush("list1", "a","b","c","d");
//2.2 弹出数据: 从右侧弹出数据
String rElement = jedis.rpop("list1");
System.out.println(rElement);
//2.3 添加数据: 从右侧添加
jedis.rpush("list2", "a","b","c","d");
//2.4 弹出数据: 从左侧弹出
String lElement = jedis.lpop("list2");
System.out.println(lElement);
//2.5 查看整个list中某个范围间的数据: start: 开始 end: 结束 0~-1 表示查询全部
List<String> list = jedis.lrange("list1", 0, -1);
System.out.println(list);
//2.6 获取元素中个数
Long llen = jedis.llen("list2");
System.out.println(llen);
//2.7 在 b元素之前插入0
jedis.linsert("list1", LIST_POSITION.BEFORE, "b", "0");
//2.8 在 c元素的后面插入1
jedis.linsert("list1", LIST_POSITION.AFTER, "c", "1");
//2.9 将最后一个元素弹出并将其添加某个list的头部(也可以是自己)
jedis.rpoplpush("list1", "list1");
list = jedis.lrange("list1", 0, -1);
System.out.println(list);
//3. 释放资源
jedis.close();
}
4.3.3 使用jedis操作redis --> hash
/**
- 使用jedis操作redis --> hash
- redis中hash和java中的hashMap类似
- hash的应用场景:
-
做缓存(目前使用较少,大部分的业务场景可以被String替代掉)
*/
@Test
public void jedisOfHash() {
//1. 创建jedis对象
Jedis jedis = new Jedis();
//2.执行操作hash的相关API
//2.1 添加数据
jedis.hset("persion", "name", "隔壁老王");
jedis.hset("persion", "age", "30");
jedis.hset("persion", "birthday", "1988年9.15");
//2.2 获取数据
String name = jedis.hget("persion", "name");
String age = jedis.hget("persion", "age");
String birthday = jedis.hget("persion", "birthday");
//2.3 一次性获取多个hash中的key的值
List<String> values = jedis.hmget("persion", "name","age");
System.out.println(values);
//2.4 获取hash所有的数据
Map<String, String> map = jedis.hgetAll("persion");
for (String key : map.keySet()) {
System.out.println(key+" "+ map.get(key));
}
//2.5 获取map中所有的key 和 所有的value
Set<String> hkeys = jedis.hkeys("persion");
List<String> hvals = jedis.hvals("persion");
System.out.println(hkeys );
System.out.println(hvals );
//2.6 删除map中的某个key
jedis.hdel("persion", "name","age"); //删除map的name和age
//2.7 删除整个map
jedis.del("persion");
//3. 释放资源
jedis.close();
}
4.3.4 使用jedis操作redis --> set
/*
* 使用jedis 操作 redis --> set
*
* set特点: 无序 不重复
*
* set的应用场景: 去重操作
*/
@Test
public void jedisOfSet() {
//1. 创建jedis的对象
Jedis jedis = new Jedis("192.168.72.144",6379);
//2. 执行set相关操作
//2.1 添加数据
jedis.sadd("set1", "a","b","c","d");
jedis.sadd("set2", "a","e","f","d");
//2.2 获取数据
Set<String> setList = jedis.smembers("set1");
System.out.println(setList);
//2.3 删除set中的指定的值
jedis.srem("set1", "b","d");
//2.4 判断某个袁术在set集合中是否存在
Boolean is = jedis.sismember("set1", "b");
System.out.println(is);
//2.5 求两个set的集合 [交 并 差]
// sdiff: 差集 sinter: 交集 sunion:并集
Set<String> sinter = jedis.sinter("set1","set2"); //求交集
System.out.println(sinter);
//2.6 查看set集合中一共有多少个数据
Long size = jedis.scard("set1");
System.out.println(size);
//3. 释放资源
jedis.close();
}
4.3.5 使用jedis操作redis -->sortedSet
/*
- 使用jedis来操作redis --> sortedSet集合
- soredSet 特点: 有序 去重复
- sortedSet的的应用场景:
-
排行榜
*/
@Test
public void jedisOfsortedSet() {
//1. 创建jedis对象
Jedis jedis = new Jedis(“192.168.72.144”,6379);
//2. 执行sortedSet的相关的操作
//2.1 添加数据
jedis.zadd("math", 98.2, "老王");
jedis.zadd("math", 59.9,"小明");
jedis.zadd("math", 79,"老张");
jedis.zadd("math", 59.2,"小李");
//2.2 获取某个成员的分数
Double zscore = jedis.zscore("math", "老张");
System.out.println(zscore);
//2.3 查看sortedSet中某个元素的排名: 从小到大
Long zrank = jedis.zrank("math", "小李");
System.out.println(zrank);
//2.4 查看sortedSet中的元素: 从大到小
Set<Tuple> zrevrange = jedis.zrevrangeWithScores("math", 0, -1);
for (Tuple tuple : zrevrange) {
String element = tuple.getElement();
double score = tuple.getScore();
System.out.println(element+" "+ score);
}
//2.4 查看sortedSet中的元素: 从小到大
Set<Tuple> zrange = jedis.zrangeWithScores("math", 0, -1);
for (Tuple tuple : zrange) {
String element = tuple.getElement();
double score = tuple.getScore();
System.out.println(element+" "+ score);
}
//2.5 删除某个元素
jedis.zrem("math", "老张");
//3. 释放资源
jedis.close();
}
5. jedis连接池
当创建jedis的对象的时候, jedis会连接redis的服务器, 获取一个连接, 如果频繁的创建一个连接, 会造成资源的消耗, 在mysql中如果发生这样的现象, 采用的是连接池的技术,提前创建好几个连接,反复使用即可, 在redis中同样也是如此。
jedis在jar中, 已经提供了一个jedis的连接池 叫 jedisPool。
连接池的基本使用
/*
* jedis连接池的基本使用
*/
@Test
public void jedisPoolOfTest() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisPool jedisPool = new JedisPool(poolConfig, "192.168.72.144", 6379);
Jedis jedis = jedisPool.getResource();
String pong = jedis.ping();
System.out.println(pong);
jedis.close();//归还连接
}
抽取一个工具类,专门用来从连接池中获取jedis的连接对象
package com.itheima.jedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisUtils {
private static JedisPool jedisPool;
static {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(5);//闲时最大的数量
poolConfig.setMaxTotal(100); //最大有100个
poolConfig.setMinIdle(3);//最小闲时的数量
jedisPool = new JedisPool(poolConfig, "192.168.72.144", 6379);
}
public Jedis getJedis() {
return jedisPool.getResource();
}
}
6. redis的持久化
我们知道, redis是将数据存储在了内存当中, 那么当关闭服务器, 内存的资源也就会消失了, 这时存储在redis中的数据也会消失, 那么我们应该如何做呢?
在redis中已经提供了两种持久化的方案
RDB: redis提供的一种基于快照机制实现的持久化方案, 而快照就类似于照相机, 会将一个服务器某个时刻的一个状态整体保存下来, 快照文件一般都非常的小,只有几kb左右
优点: 由于持久化的文件非常小, 适合于做灾难恢复
缺点: 由于redis中持久化的时机问题, 会存在数据丢失的问题
AOF: redis提供的一种基于日志机制实现的持久化方案, 会将用户操作的所有的命令整体的记录下来保存到日志文件中,一般文件都比较庞大
优点: AOF机制可以让将用户所有的命令都记录下来, 顾其数据保存的比较完整, 不容易丢失
缺点: 持久化的文件比较庞大, 不利于灾难恢复
RDB保存机制: redis默认是开启RDB机制
save 900 1 : 在900秒之内,如果有一个数据进行修改,就会执行一下保存
save 300 10 : 在300秒之内, 如果有10个以上的数据被修改, 就会执行一下保存
save 60 10000 : 在60秒之内, 如果有10000个以上的数据被修改. 就会执行一下保存
当服务器宕机, 最大丢失数据量为在不到5分钟的时间里丢掉9999个数据
一般情况下redis的不会出现宕机的现象, 除非redis中的数据将内存撑爆了, 但这个现象在大公司是不会出现的
AOF的保存机制:redis默认不开启
如何开启AOF:
打开redis的配置文件,修改下列两个参数即可
appendonly yes //默认此项是no,没有启动AOF机制
appendfsync everysec //appendfsync的取值: [always everysec no]
always: 总是, 只要有新的命令执行, 就将其保存到文件中
优点: 数据保存最完整, 几乎不会丢掉数据
缺点: 大大降低了redis的性能
everysec: 每秒钟执行一次保存
此种保存不会大幅度的降低redis的性能,但是会丢失最大1s的数据
no: 不执行保存, 由操作系统自动调用保存(linux一般30分钟刷新一次内存)
一般不使用