###前言
昨天和室友去包夜,玩了一晚上的
LOL,跪了一整夜,但是很开心。从S1末开始玩LOL的我,到现在还是青铜,真是菜的抠脚。最近负能力满满的,唯有睡觉和学习才可解忧愁。今天也看了慕课网上面的《Redis入门》,来记一下学习笔记。(写这篇文章开头的时候应该是一个星期之前)

###NoSQL概述
-
NoSQL就是Not Only SQL的意思,是非关系型数据库。 -
为什么需要
NoSQL?-
High performance- 高并发读写 -
Huge Storage- 海量数据的高效率存储和访问 -
High Scalability & High Availability- 高可扩展性和高可用性
-
-
NoSQL数据库的四大分类
-
键值(
Key - Value)存储:优点是快速查询,缺点存储的数据缺少结构化。 -
列存储:优点是查询比较快,扩展性比较强,缺点是功能相对局限。
-
文档数据库:对应的产品就是
MongoDB。对数据结构要求不是特别严格,查询性能不能特别高,缺少统一查询的语法。 -
图形数据库:优点是利用图结构相关的算法,缺点是需要对整个图进行结算才能得出结果,不能作为分布式的解决方案。
-

- 现在来说说
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,测试成功。
-
我们在
Xshell软件,输入get name指令,也可以看到输出cmazxiaoma。
###Redis的数据结构
####String
-
Key定义的注意点:- 不要过长。
- 不要过短。
- 统一的命名规范。
-
存储
String:- 二进制安全的,存入和获取的数据相同。
Value最多可以容纳的数据长度是512M。
-
存储
String常用的命令:-
赋值

-
取值

-
删除

-
数值增减
-
如果属性不存在的话,那么integer类型默认为0。

如果name属性的值不能转换成integer类型,那么会抛出ERR is not an integer or out of range异常。

decr指令也是一样的。

- 扩展命令
incrby、decrby也是一样的,很简单。
append指令可以拼接字符串。

如果append key cmazxiaoma。这个key不存在的话,首先会创建这个key,然后存入cmazxiaoma内容,接着输出cmazxiaoma。

####Hash
-
赋值,可以使用
hset myhash key value单一赋值、hmset myhash key value key value多次赋值。
-
取值,可以用
hget myhash key单一取值、hmget myhash key key多个取值、hgetall取出所有key所对应的值。
-
删除 ,可以用
hdel myhash key删除单一的key。
hdel myhash key key删除多个的key。

del myhash删除myhash中所有的key。

-
数值增减,
hincrby myhash key 100
-
使用
hexists myhash key判断key是否在myhash中存在,存在返回1,不存在返回0。
-
hlen myhash获取myhash中存在key的数量。
-
hkeys myhash获取myhash中所有的key。
-
hvals myhash获取myhash中所有的values。
####List
-
存储list:
ArrayList使用数组方式LinkedList使用双向链表方式
-
两端添加
- 使用
lpush a b c命令在左端添加,那么c肯定是在最左端。
- 使用
rpush a b c命令在右端添加,那么c肯定是在最右端。
- 使用
-
两端弹出
- 使用
lpop mylist弹出mylist中头部元素、rpop mylist2弹出mylist2尾部中的元素。它们都是3。
- 我们接着来查看
mylist、mylist2。
- 使用
-
查看列表
- 使用
lrange mylist 0 5来查看mylist列表,mylist插入的方式从头结点开始添加的,那么输出肯定是321abc。
- 使用
lrange mylist2 0 5查看mylist2列表,mylist2插入的方式是从最右端添加的,那么输出肯定是abc123
- 使用

-
获取列表元素的个数
- 使用
llen mylist命令
- 使用
-
扩展命令
-
使用
lpushx mylist x,使插入的元素在头部位置。
-
使用
rpushx mylist x,使插入的元素在尾部位置。
-
使用
lrem mylist count element,count代表是删除的次数,element代表是需要删除的元素。如果count > 0代表删除的方式从头到尾,删除count个element,count < 0代表删除的方式从尾到头,删除count个element。如果count = 0,删除mylist中所有和element相同的元素。

-
lrem mylist 2 test1
-
lrem mylist -2 test1
-
lrem mylist 0 cmazxiaoma
-
在某一个下标位置插入元素。
lset mylist index element
-
在目标元素之前插入指定的元素。
linsert mylist before helloworl before_helloworld

-
在目标元素之后插入指定的元素。
linsert mylist helloworld after after_helloworld
-
弹出
mylist中最后一个元素,并插入到mylist中的头部。rpoplpush mylist mylist
-
rpoplpush使用场景
-
####Set
和List类型不同的是,Set集合中不允许出现重复的元素。
-
添加/删除元素
- 添加
sadd myset a b c,如果我们重复添加相同的元素,肯定是不成功的。比如sadd myset a。
- 删除
srem myset a,删除myset中的a元素。
- 查看
myset中的元素。smembers myset
- 查看指定元素是否是
myset中的成员。sismember myset a,返回0代表不存在,返回1代表存在。
- 添加
-
获得集合中的元素,
smembers myset -
集合中的差集运算,
sdiff myset2 myset。myset2中元素有b,c,d。myset中元素有b,c。它们之间的差集运算结果应该为d。
-
集合中的交集运算,
sinter myset2 myset,应该输出cb。
-
集合中的并集运算,
sunion myset2 myset,应该输出cbd。
-
-
扩展命令
-
scard myset查看myset有多少个元素。
-
srandmember myset随机返回myset中的一个元素。
-
sdiffstore new_myset myset2 myset把myset和myset2差集元素的结果存储到new_myset中。(sinterstore,sunionstore也是一样的用法)
-
-
Set使用场景
- 跟踪一些唯一性的数据。
- 用于维护数据对象之间的关联关系。
####SortedSet
SortedSet中的成员在集合中的位置是有序的。
-
添加元素
zadd mysort 70 cmazxiaoma 80 xiaoma 100 doudou
-
获得元素
-
zcard mysort获得mysort中所有元素的个数
-
获得
mysort中name为cmazxiaoma对应的成绩。zscore mysort cmazxiaoma
-
-
删除元素,
zrem mysort cmazxiaoma deli doudou xiaoma
-
范围查询
zrange mysort 0 -1,输出的key是按成绩正序排列。
-
如果输出的数据项要带上成绩的话,指令应该是
zrange mysort 0 -1 withscores
-
如果输出的数据项想按成绩逆序排序,那么就应该
zrevrange mysort 0 -1 withscores
-
如果想按排名范围进行删除的话,那么应该
zremrangebyrank mysort 0 2
-
如果想按成绩范围进行删除的话,那么应该
zremrangebyscore mysort 0 10。顾名思义删除成绩在0-10之内的数据项。
-
-
扩展命令
-
查看分数在
0-10之内的学生信息,zrangebyscore mysort 0 10 withscores
-
查看分数在
0-100之内且在第1行-第2行的学生信息。zrangebyscore mysort 0 100 withiscores limit 0 2
-
给
cmazxiaoma的成绩加100分。zincrby mysort cmazxiaoma 100
-
查看成绩
0-10之间的学生的个数。zcount mysort 0 10
-
-
Sorted Set使用场景-
如大型在线游戏积分排行榜
-
构建索引数据
-
###Redis中的通用命令
-
key *获取所有redis中的key
-
keys my*获取所有redis中以my开头的key
-
exists mylist查看redis中是否存在mylist,0代表不存在,1代表存在。
-
rename name new_name给名字为name的数据结构重命名为new_name
-
expire new_name 10设置redis中new_name过期时间,通过ttl new_name看到其距离过期的时间。
-
type mylist,可以查看mylist对应的数据结构类型。
###Redis的事务
-
Redis相关的特性:-
多数据库
-
Redis事务
-
-
一个
Redis最多可以提供16个数据库,下标分别是0-15。客户端默认连接的是第0号数据。我们可以通过select index来选择数据库。
-
我们想把第
0号的数据库中某些key移动到第1号数据库里面,那么我们该怎么做呢。通过move cmazxiaoma_test_mayday_5 1就可以完成。
-
我们可以通过
multi、exec、discard来完成事务操作。事务执行期间,Redis不会为其他客户端提供任何服务,以保证事务中的所有命令原子执行。multi相当于开启事务,exec相当于提交,discard相当于回滚。 -
首先我们在第一个客户端进行如下操作。我们在第一个客户端开启了事务,在事务中我们
incr num2次,按理来说,get num应该等于4。
-
我们在第二个客户端输入
get num,发现num还是2。那么证明了我们的结论:事务执行期间,Redis不会为其他客户端提供任何服务,以保证事务中的所有命令原子执行。
-
如果我们在第一个客户端提交了事务。

-
接着我们在第二个客户端
get num,发现可以num的值得到了更新。
-
我们可以演示一下回滚操作,首先
set user cmazxiaoma,接着开启事务,在事务中set user xiaoma,然后进行回滚操作,发现get user依然是cmazxiaoma。
###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打开配置文件,可以看到以下配置。
-
同时我们还可以看到内存快照输出在
file文件名。
优缺点:
-
如果数据集很大,
RDB相对于AOF启动效率很更高。 -
如果想保证数据的高可用性,最大限度的避免数据的丢失,
RDB将不是一个好的选择。因为系统在定时持久化操作之前,还没来得及在硬盘写入数据就发生宕机的话,就造成了数据的丢失。 -
RDB通过fork出子线程来完成数据持久化操作,如果当数据集很大的时候,可能会导致服务器停止几百ms,或者几s。
-

-
AOF(append only file): -
对于
Redis服务器而言,其缺省的机制是RDB,如果需要使用AOF,则需要修改appendonly no改成appendonly yes。Redis在每一次收到数据修改的命令之后,都会将其追加到AOF文件中。在Redis下一次重新启动时,需要加载AOF文件中的信息来构建最新的数据到内存中。

-
可以记录服务器的所有写操作。在服务器重新启动时,会把所有的写操作重新执行一遍从而实现数据的备份。当写操作集过大(比原有的数据集还大),
Redis会重写写操作集。 -
带来更好的数据安全性,有
3种同步策略,每秒同步,每修改同步,不同步。 每秒同步也是异步完成的,效率也非常高。缺点是一旦系统发生宕机的现象,那么这一秒中的修改的数据就会发生丢失。每修改同步,我们可以视为同步持久化。每一次发生数据的变化,就会立即的记录在磁盘,这种效率很低,但是很安全。 -
采用
append追加的模式,就算系统发生宕机,也不会影响我们日志文件中已经存在的内容。然而我们本次操作中,只写入了一半数据就出现了系统崩溃的问题。在Redis下一次启动之前,我们可以通过"redis-check-aof --fix <filename>"命令来修复坏损的AOF文件,解决数据一致性的问题。 -
对于相同数量的数据集而言,
AOF文件通常要大于RDB文件。 -
AOF在运行效率上往往会慢于RDB。

RDB和AOF的区别 前者是保存了数据本身,而后者是记录了数据的变更。
###尾言
这篇文章最后在网吧完成的,勿以善小而不为。