前言
昨天和室友去包夜,玩了一晚上的
LOL
,跪了一整夜,但是很开心。从S1
末开始玩LOL
的我,到现在还是青铜,真是菜的抠脚。最近负能力满满的,唯有睡觉和学习才可解忧愁。今天也看了慕课网上面的《Redis
入门》,来记一下学习笔记。(写这篇文章开头的时候应该是一个星期之前)
DNA.png
NoSQL概述
NoSQL
就是Not Only SQL
的意思,是非关系型数据库。为什么需要
NoSQL
?High performance
– 高并发读写Huge Storage
– 海量数据的高效率存储和访问High Scalability & High Availability
– 高可扩展性和高可用性
NoSQL数据库的四大分类
键值(
Key - Value
)存储:优点是快速查询,缺点存储的数据缺少结构化。列存储:优点是查询比较快,扩展性比较强,缺点是功能相对局限。
文档数据库:对应的产品就是
MongoDB
。对数据结构要求不是特别严格,查询性能不能特别高,缺少统一查询的语法。图形数据库:优点是利用图结构相关的算法,缺点是需要对整个图进行结算才能得出结果,不能作为分布式的解决方案。
image.png
- 现在来说说
NoSQL
的特点,美滋滋。- 易扩展
- 灵活的数据模型
- 高可用
- 大数据量,高性能
Redis的概述
高性能键值对数据库,支持的键值数据类型:
字符串类型 –
String
列表类型 –
Set
有序集合类型 –
Sorted Set
散列类型 –
Hash
集合类型 –
List
Redis
的应用场景缓存
任务队列
网站访问统计
应用排行榜
分布式集群架构中的session分离
Redis在Linux上的使用
可以看我这篇文章【Linux学习】 Redis常用的一些指令
Jedis的入门
- 我们要在
Java
平台上使用redis
,肯定需要Jedis
这个客户端。首先在pom
文件中引入Jedis
的依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
- 普通方式创建Jedis对象。
public void methodOne() {
Jedis jedis = new Jedis("100.64.84.47", 6379);
jedis.set("name", "cmazxiaoma");
String value = jedis.get("name");
System.out.println(value);
jedis.close();
}
- 通过线程安全的连接池来创建Jedis对象。
public void methodTwo() {
//获得连接池的配置对象
JedisPoolConfig config = new JedisPoolConfig();
//设置最大连接数
config.setMaxTotal(30);
//设置最大空闲连接数
config.setMaxIdle(10);
//获得连接池
JedisPool jedisPool = new JedisPool(config, "100.64.84.47", 6379);
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String value = jedis.get("name");
System.out.println(value);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
jedisPool.close();
}
}
}
- 编写测试类。
public class JedisDemo1Test {
private JedisDemo1 demo;
@Before
public void setUp() {
demo = new JedisDemo1();
}
@Test
public void methodOne() throws Exception {
demo.methodOne();
}
@Test
public void methodTwo() throws Exception {
demo.methodTwo();
}
}
运行
Test Case
,测试成功。image.png
我们在
Xshell
软件,输入get name
指令,也可以看到输出cmazxiaoma
。image.png
Redis的数据结构
String
Key
定义的注意点:- 不要过长。
- 不要过短。
- 统一的命名规范。
存储
String
:- 二进制安全的,存入和获取的数据相同。
-
Value
最多可以容纳的数据长度是512M
。
存储
String
常用的命令:赋值
image.png
取值
image.png
删除
image.png
数值增减
如果属性不存在的话,那么integer
类型默认为0
。
image.png
如果name
属性的值不能转换成integer
类型,那么会抛出ERR is not an integer or out of range
异常。
image.png
decr
指令也是一样的。
image.png
- 扩展命令
incrby
、decrby
也是一样的,很简单。
image.png
append
指令可以拼接字符串。
image.png
如果append key cmazxiaoma
。这个key
不存在的话,首先会创建这个key
,然后存入cmazxiaoma
内容,接着输出cmazxiaoma
。
image.png
Hash
赋值,可以使用
hset myhash key value
单一赋值、hmset myhash key value key value
多次赋值。image.png
取值,可以用
hget myhash key
单一取值、hmget myhash key key
多个取值、hgetall
取出所有key
所对应的值。image.png
删除 ,可以用
hdel myhash key
删除单一的key
。image.png
hdel myhash key key
删除多个的key
。
image.png
del myhash
删除myhash
中所有的key
。
image.png
数值增减,
hincrby myhash key 100
image.png
使用
hexists myhash key
判断key
是否在myhash
中存在,存在返回1
,不存在返回0
。image.png
hlen myhash
获取myhash
中存在key
的数量。image.png
hkeys myhash
获取myhash
中所有的key
。image.png
hvals myhash
获取myhash
中所有的values
。image.png
List
存储list:
-
ArrayList
使用数组方式 -
LinkedList
使用双向链表方式
-
两端添加
- 使用
lpush a b c
命令在左端添加,那么c
肯定是在最左端。
image.png - 使用
rpush a b c
命令在右端添加,那么c
肯定是在最右端。
image.png
- 使用
两端弹出
- 使用
lpop mylist
弹出mylist
中头部元素、rpop mylist2
弹出mylist2
尾部中的元素。它们都是3
。
image.png - 我们接着来查看
mylist
、mylist2
。
image.png
- 使用
- 查看列表
- 使用
lrange mylist 0 5
来查看mylist
列表,mylist
插入的方式从头结点开始添加的,那么输出肯定是321abc
。
image.png - 使用
lrange mylist2 0 5
查看mylist2
列表,mylist2
插入的方式是从最右端添加的,那么输出肯定是abc123
image.png
- 使用
image.png
获取列表元素的个数
- 使用
llen mylist
命令
image.png
- 使用
扩展命令
使用
lpushx mylist x
,使插入的元素在头部位置。image.png
使用
rpushx mylist x
,使插入的元素在尾部位置。image.png
使用
lrem mylist count element
,count
代表是删除的次数,element
代表是需要删除的元素。如果count > 0
代表删除的方式从头到尾,删除count
个element
,count < 0
代表删除的方式从尾到头,删除count
个element
。如果count = 0
,删除mylist
中所有和element
相同的元素。image.png
image.pnglrem mylist 2 test1
image.png
lrem mylist -2 test1
image.png
lrem mylist 0 cmazxiaoma
image.png
在某一个下标位置插入元素。
lset mylist index element
image.png
在目标元素之前插入指定的元素。
linsert mylist before helloworl before_helloworld
image.png
image.png在目标元素之后插入指定的元素。
linsert mylist helloworld after after_helloworld
image.png
弹出
mylist
中最后一个元素,并插入到mylist
中的头部。rpoplpush mylist mylist
image.png
rpoplpush
使用场景image.png
Set
和List
类型不同的是,Set
集合中不允许出现重复的元素。
- 添加/删除元素
- 添加
sadd myset a b c
,如果我们重复添加相同的元素,肯定是不成功的。比如sadd myset a
。
image.png - 删除
srem myset a
,删除myset
中的a
元素。
image.png - 查看
myset
中的元素。smembers myset
image.png - 查看指定元素是否是
myset
中的成员。sismember myset a
,返回0
代表不存在,返回1
代表存在。
image.png
- 添加
获得集合中的元素,
smembers myset
集合中的差集运算,
sdiff myset2 myset
。myset2
中元素有b,c,d
。myset
中元素有b,c
。它们之间的差集运算结果应该为d
。image.png
集合中的交集运算,
sinter myset2 myset
,应该输出cb
。image.png
集合中的并集运算,
sunion myset2 myse
t,应该输出cbd
。image.png
扩展命令
scard myset
查看myset
有多少个元素。image.png
srandmember myset
随机返回myset
中的一个元素。image.png
sdiffstore new_myset myset2 myset
把myset
和myset2
差集元素的结果存储到new_myset
中。(sinterstore
,sunionstore
也是一样的用法)image.png
Set使用场景
- 跟踪一些唯一性的数据。
- 用于维护数据对象之间的关联关系。
SortedSet
SortedSet
中的成员在集合中的位置是有序的。
添加元素
zadd mysort 70 cmazxiaoma 80 xiaoma 100 doudou
image.png
获得元素
zcard mysort
获得mysort
中所有元素的个数image.png
获得
mysort
中name
为cmazxiaoma
对应的成绩。zscore mysort cmazxiaoma
image.png
删除元素,
zrem mysort cmazxiaoma deli doudou xiaoma
image.png
范围查询
zrange mysort 0 -1
,输出的key
是按成绩正序排列。image.png
如果输出的数据项要带上成绩的话,指令应该是
zrange mysort 0 -1 withscores
image.png
如果输出的数据项想按成绩逆序排序,那么就应该
zrevrange mysort 0 -1 withscores
image.png
如果想按排名范围进行删除的话,那么应该
zremrangebyrank mysort 0 2
image.png
如果想按成绩范围进行删除的话,那么应该
zremrangebyscore mysort 0 10
。顾名思义删除成绩在0-10
之内的数据项。image.png
扩展命令
查看分数在
0-10
之内的学生信息,zrangebyscore mysort 0 10 withscores
image.png
查看分数在
0-100
之内且在第1
行-第2
行的学生信息。zrangebyscore mysort 0 100 withiscores limit 0 2
image.png
给
cmazxiaoma
的成绩加100
分。zincrby mysort cmazxiaoma 100
image.png
查看成绩
0-10
之间的学生的个数。zcount mysort 0 10
image.png
Sorted Set
使用场景如大型在线游戏积分排行榜
构建索引数据
Redis中的通用命令
key *
获取所有redis中的keyimage.png
keys my*
获取所有redis
中以my
开头的key
image.png
exists mylist
查看redis
中是否存在mylis
t,0
代表不存在,1
代表存在。image.png
rename name new_name
给名字为name
的数据结构重命名为new_name
image.png
expire new_name 10
设置redis
中new_name
过期时间,通过ttl new_name
看到其距离过期的时间。image.png
type mylist
,可以查看mylist
对应的数据结构类型。image.png
Redis的事务
Redis
相关的特性:多数据库
Redis
事务
一个
Redis
最多可以提供16
个数据库,下标分别是0-15
。客户端默认连接的是第0
号数据。我们可以通过select index
来选择数据库。image.png
我们想把第
0
号的数据库中某些key
移动到第1
号数据库里面,那么我们该怎么做呢。通过move cmazxiaoma_test_mayday_5 1
就可以完成。image.png
我们可以通过
multi
、exec
、discard
来完成事务操作。事务执行期间,Redis
不会为其他客户端提供任何服务,以保证事务中的所有命令原子执行。multi
相当于开启事务,exec
相当于提交,discard
相当于回滚。首先我们在第一个客户端进行如下操作。我们在第一个客户端开启了事务,在事务中我们
incr num
2
次,按理来说,get num
应该等于4
。redis第一个客户端.png
我们在第二个客户端输入
get num
,发现num
还是2
。那么证明了我们的结论:事务执行期间,Redis
不会为其他客户端提供任何服务,以保证事务中的所有命令原子执行。image.png
如果我们在第一个客户端提交了事务。
image.png
接着我们在第二个客户端
get num
,发现可以num
的值得到了更新。image.png
我们可以演示一下回滚操作,首先
set user cmazxiaoma
,接着开启事务,在事务中set user xiaoma
,然后进行回滚操作,发现get user
依然是cmazxiaoma
。image.png
Redis的持久化
Redis
的性能体现在它把数据都保存在内存当中。我们把内存中的数据同步到硬盘当中的操作称之为持久化。
Redis
持久化方式:RDB
方式,在指定的时间内,把内存中的数据快照写入到硬盘当中。AOF
方式,将以日志的形式记录服务器所处理的每一个操作。当Redis
服务器启动之初,它会读取该aof
文件,会重新构建我们的数据库。保证我们启动之后,保证数据的完整性。无持久化,我们可以通过配置禁止
Redis
服务器的持久化,我们认为Redis
就是缓存的一种机制了。同时使用。
RDB
:默认情况下,每隔一段时间
redis
服务器程序会自动对数据库做一次遍历,把内存快照写在一个叫做"dump.rdb"
的文件里,这个持久化机制叫做SNAPSHOT
。有了SNAPSHOT
后,如果服务器宕机,重新启动redis
服务器时,redis
会自动加载"dump.rdb"
,将数据库状态恢复上一次SNAPSHOT
的状态。Redis
服务器初始化过程中,设定了定时时间,每隔一段时间就会触发持久化操作,进入定时事件处理程序中,就会fork
出子进程来进行持久化操作。Redis
服务器预设了save
指令,客户端可要求服务器进程中断服务,执行持久化操作。我们可以通过
vim /etc/redis.conf
打开配置文件,可以看到以下配置。image.png
同时我们还可以看到内存快照输出在
file
文件名。image.png
优缺点:
如果数据集很大,
RDB
相对于AOF
启动效率很更高。如果想保证数据的高可用性,最大限度的避免数据的丢失,
RDB
将不是一个好的选择。因为系统在定时持久化操作之前,还没来得及在硬盘写入数据就发生宕机的话,就造成了数据的丢失。RDB
通过fork
出子线程来完成数据持久化操作,如果当数据集很大的时候,可能会导致服务器停止几百ms
,或者几s
。
RDB.png
AOF
(append only file
):对于
Redis
服务器而言,其缺省的机制是RDB
,如果需要使用AOF
,则需要修改appendonly no
改成appendonly yes
。Redis
在每一次收到数据修改的命令之后,都会将其追加到AOF
文件中。在Redis
下一次重新启动时,需要加载AOF
文件中的信息来构建最新的数据到内存中。image.png
image.png可以记录服务器的所有写操作。在服务器重新启动时,会把所有的写操作重新执行一遍从而实现数据的备份。当写操作集过大(比原有的数据集还大),
Redis
会重写写操作集。带来更好的数据安全性,有
3
种同步策略,每秒同步,每修改同步,不同步。 每秒同步也是异步完成的,效率也非常高。缺点是一旦系统发生宕机的现象,那么这一秒中的修改的数据就会发生丢失。每修改同步,我们可以视为同步持久化。每一次发生数据的变化,就会立即的记录在磁盘,这种效率很低,但是很安全。采用
append
追加的模式,就算系统发生宕机,也不会影响我们日志文件中已经存在的内容。然而我们本次操作中,只写入了一半数据就出现了系统崩溃的问题。在Redis下一次启动之前,我们可以通过"redis-check-aof --fix <filename>"
命令来修复坏损的AOF
文件,解决数据一致性的问题。对于相同数量的数据集而言,
AOF
文件通常要大于RDB
文件。AOF
在运行效率上往往会慢于RDB
。
AOF.png
-
RDB
和AOF
的区别
前者是保存了数据本身,而后者是记录了数据的变更。
尾言
这篇文章最后在网吧完成的,勿以善小而不为。