前言
昨天和室友去包夜,玩了一晚上的
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的区别
前者是保存了数据本身,而后者是记录了数据的变更。
尾言
这篇文章最后在网吧完成的,勿以善小而不为。
本文介绍了NoSQL数据库的概念及其特点,重点讲解了Redis的基本使用方法、数据结构及应用场景,并探讨了Redis的事务处理和持久化机制。
1690

被折叠的 条评论
为什么被折叠?



