Redis学习手册

我的个人博客Alexios,欢迎大家来吐槽交流。

一、NoSQL

NoSQL = Not Only SQL,不仅仅是SQL,泛指非关系数据库

使用场景:数据变化不是很频繁,访问量相对较大

二、Redis入门

2.1、概述

  • Redis指Remote Dictionary Server,即远程字典服务

  • 一个开源的由ANSI C语言编写,支持网络、可基于内存也可持久化的日志型Key-value数据库,支持多种语言

  • redis会周期性将更新的数据写入磁盘或者把修改操作写入追加的记录文件

2.2、特性

  • 开源
  • 支持多种语言
  • 支持持久化、集群和事务

2.3、基础知识

  • redis有16个数据库,默认使用第1个数据库(下标为0)
  • 使用select可以切换数据库,使用DBSIZE可以查看当前数据库的数据数量

  • 清除当前数据库:flushdb
  • 清楚所有数据库:flushall
  • redis是单线程的,redis的瓶颈是根据机器的内存和网络带宽。

三、五大数据类型

image-20210203221317019

3.1、Redis-key

EXISTS 键名,如果有这个键,返回1,否则返回0
exists 键名

image-20201011214514520

3.2、String(字符串)

1、append 键名 要追加的内容:

往已有的键值对的值中拼接新内容,如果没有该键,那么就新建一个键值对(相当于set)

set name hello
get name
输出hello
append name world
输出10-->返回拼接后值的长度
get name
输出helloworld
  • 先设置一个键值对,即name–>hello,然后往该键值对的值中拼接字符world,最后使用get name查看结果

image-20201011222603013

2、strlen 键名 :

获取该键值对中值的长度

strlen name
输出10

image-20201011222916865

3、incr 键名:

针对数值使用,让数值的值+1

  • 初始化一个键值对(views–0),然后使用incr 命令让其+1
set views 0
输出0
incr views
get views
输出1

image-20201011224023734

4、decr 键名:

同针对数值使用,让该数值的值-1

  • 将上面的views从3减到2
decr views

image-20201011224227673

5、incrby/decrby:

类似incr/decr,多了个步长

  • 将views的值从2直接加到12(步长设置为10),然后把views的值从12降到7(步长为5)
incrby views 10
decrby views 5

image-20201011224913175

6、GETRANGE 键名 起始坐标 终止坐标(类似java中String类的substring)

截取(终止坐标 - 起始坐标) + 1个字符,闭区间[起始,终止]

  • 设置一个键值对,然后截取该值的一部分

image-20201011225254904

使用GETRANGE 键名 0 -1获取值对应的整个字符串,相当于get 键名

  • 获取该键值对值的全部内容

image-20201011225441783

7、SETRANGE 键名 偏移量n 要替换的字符串

替换指定字符开始的字符串

  • 先设置一个键值对:key2–>abcdefg,然后偏移一个单位,将xx替换到目标串中

image-20201011230122084

8、setex 键名 过期时间 值

为指定的key设置值和过期时间,如果key已经存在,SETEX命令会替换旧的值

  • 先设置一个键值对,然后使用setex覆盖

image-20201011232438878

9、setnx(SET IF NOT EXISTS) 键名 值

当指定的key不存在时,为key设置指定的值,如果存在会覆盖失败,返回0,成功返回1,这个命令经常在分布式锁中用到

  • 先设置一个键值对,然后尝试使用setnx覆盖,观察结果,发现返回0,且key的值还是wuhu111

image-20201011232537974

10、mset 键1 值1 键2 值2 …

使用这个命令可以批量添加键值对

  • 添加三个键值对

image-20201011233358741

11、mget 键1 键2 …

批量取得值

  • 取得上面添加的值

image-20201011233547127

12、msetnx 键1 值1 …

同时插入多个键值对,如果有一个键已经存在,就不执行插入操作,所有键都不存在时才插入

13、设置对象

set user : 1 {username : zhuo,age : 18}

  • 使用mset和mget存储和获取对象
127.0.0.1:6379> mset user:1:name hzx user:1:age 18
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "hzx"
2) "18"

image-20201011234455595

14、getset 先取后赋值

由于是先get后set,所以注意结果是上次的值,先返回当前值,后设置新值

  • 设置一个键值对k1-v1,然后使用getset将值变为value1,观察

image-20201011235025047

15、String应用场景:

  • 由于redis中没有数值类型,所以数字也是用string存储
  • 可以用作计数器
  • 统计数量
  • 对象缓存存储

3.3、List

  • 在redis中,我们可以通过设置规则来使list成为一个栈或队列
  • 所有list命令大部分以l开头

1、LPUSH 集合名 值

将一个或多个值从左边插进列表

127.0.0.1:6379> LPUSH list one # 在列表左边插入值
(integer) 1
127.0.0.1:6379> LPUSH list two three # 在列表中插入多个值
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1  # 获取列表中所有的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> Lrange list 0 1 #获取列表中下标在[0,1]的值
1) "three"
2) "two"

2、RPUSH 集合名 值

将一个或多个值从右边插进列表

127.0.0.1:6379> Rpush list right
(integer) 4
127.0.0.1:6379> rpush list right1 right2
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
5) "right1"
6) "right2"

3、LPOP 列表名

从左边弹出(移出)一个元素

127.0.0.1:6379> LPOP list 
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "right"
4) "right1"
5) "right2"

4、RPOP 列表名

从右边弹出一个元素

127.0.0.1:6379> RPOP list
"right2"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "right"
4) "right1"

5、LINDEX 列表名 下标

通过下标获取值

127.0.0.1:6379> LINDEX list 0
"two"
127.0.0.1:6379> LINDEX list 3
"right1"

6、Llen 列表名

获取列表长度

127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
3) "right"
4) "right1"
127.0.0.1:6379> Llen list
(integer) 4

7、Lrem 列表名 移除个数 精确值

移除列表中的一个或多个值,精确匹配

127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "one"
3) "one"
4) "one"
5) "two"
6) "one"
7) "right"
8) "right1"
127.0.0.1:6379> lrem list 1 two
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "one"
3) "one"
4) "one"
5) "one"
6) "right"
7) "right1"
127.0.0.1:6379> lrem list 5 one
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "right"
2) "right1"

8、ltrim 列表名 起始坐标 结束坐标

截断列表,列表元素变为[start ,end]

127.0.0.1:6379> lrange list 0 -1
1) "hello1"
2) "hello2"
3) "hello3"
4) "hello4"
127.0.0.1:6379> ltrim list 1 2
OK
127.0.0.1:6379> lrange list 0 -1
1) "hello2"
2) "hello3"

9、exists 列表名

判断列表中有几个值

10、LSET 列表名 下标 值

替换列表指定下标的值,如果当前列表中不存在指定下标所对应的值,就报错

127.0.0.1:6379> lrange list 0 -1
1) "value3"
2) "value2"
3) "value1"
4) "hello2"
127.0.0.1:6379> lset list 0 item
OK
127.0.0.1:6379> lrange list 0 -1
1) "item"
2) "value2"
3) "value1"
4) "hello2"

11、LINSERT 列表名 前|后 要插入的位置 要插入的值

在列表的某个值前|后插入一个值

127.0.0.1:6379> rpush list hello
(integer) 1
127.0.0.1:6379> rpush list world
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "world"
# 在world单词前插入一个值:other
127.0.0.1:6379> linsert list before "world" other
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "world"
  • 往上面list的other元素后插入一个值wuhu
127.0.0.1:6379> linsert list after "other" wuhu
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "wuhu"
4) "world"

12、小结:

  • list实际上是一个链表,所以可以在节点前后插入节点,也可以在最左端、最右端插入元素

  • 如果key不存在,创建新的链表

  • 如果key存在,新增内容

  • 如果移除了key,那么链表被移除

  • 在两边插入或改动值效率最高!操作中间值效率会降低

  • 可以用来模拟栈(LPUSH、LPOP)、消息队列(LPUSHR、RPOP)

四、事务

4.1、介绍

Redis事务是一个单独的隔离过程:事务中的所有命令都会被序列化、按顺序地执行。事务在执行过程中不会被其他客户端发送来的命令请求所打断,redis事务的主要作用就是串联多个命令防止别的命令插队。

4.2、Redis事务的特性

单独的隔离操作:

  • 事务中的所有命令都会被序列化、按顺序地执行。事务在执行过程中不会被其他客户端发送来的命令请求所打断

没有隔离级别的概念

  • 队列中的命令没有提交之前都不会实际的被执行。

不保证原子性

  • Redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

4.3、使用

  • 开启事务(multi)
  • 命令入队
  • 执行事务(exec)

正常执行事务

  • 使用redis事务
127.0.0.1:6379> multi    # 开启事务
OK
127.0.0.1:6379> set k1 v1   # QUEUED代表命令入队列
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 1
QUEUED
127.0.0.1:6379> incr k4
QUEUED
127.0.0.1:6379> exec       # exec代表执行事务
1) OK
2) OK
3) "v1"
4) OK
5) OK
6) (integer) 2

放弃事务(discard)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 1
QUEUED
127.0.0.1:6379> incrby k3 50
QUEUED
127.0.0.1:6379> decrby k3 26
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> get k3
(nil)         #放弃事务后发现k3值为null

(报告错误)编译型异常(代码/命令有问题),事务中所有命令都不会被执行

(执行错误)运行时异常(例如:1/0或空指针),如果事务队列中存在运行时异常,那么这条发生异常的命令不会被执行,其他命令继续执行(redis事务没有一致性),错误命令抛出异常

原子性:指事务的不可分割性,一个事务的所有操作要么不间断地全部被执行,要么一个也没有执行。

4.4、注意点

Redis单条命令是保证原子性的,但是Redis的事务是不保证原子性的!

4.5、监控

1、悲观锁

  • 无论做什么都加锁(会影响性能)

2、乐观锁

  • 认为什么时候都不会出问题,所以不会上锁!更新数据时去判断以下期间有没有人修改过此数据。
  • mysql中:获取version,比较version

image-20210203224610835

3、使用watch来监控

在执行multi之前,先执行watch key1 [key2],可以监视一个或多个key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断

  • 正常执行成功
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money       #使用watch监视money对象
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

五、Jedis

JRedis是Redis官方推荐的java连接开发工具,使用java操作redis的中间件,类似JDBCDriver

5.1、常用API

1、导入依赖


<dependency><groupId>redis.clientsgroupId><artifactId>jedisartifactId><version>3.2.0version>
dependency>
<dependency><groupId>com.alibabagroupId><artifactId>fastjsonartifactId><version>1.2.62version>
dependency>

2、编码测试

使用Jedis连接Redis

public class TestPing {public static void main(String[] args) {//1 new 一个Jedis对象,构造参数填入地址和端口号Jedis jedis = new Jedis("127.0.0.1", 6379);//jedis 的函数就是我们之前学习的所有命令System.out.println(jedis.ping());}
}

结果

image-20210203225023793

3、操作命令

Jedis的方法和上面的命令几乎一样,这里列出Redis-key的

        Jedis jedis = new Jedis("127.0.0.1",6379);System.out.println("清空指定数据库中的数据:" + jedis.flushDB());System.out.println("清空所有数据:" + jedis.flushAll());System.out.println("新增<'username','wuhu'>的键值对:" + jedis.set("username","wuhu"));System.out.println("新增<'password','qifei'>的键值对:" + jedis.set("password","qifei"));System.out.print("系统中所有的键如下:");Set<String> keys = jedis.keys("*");System.out.println(keys);System.out.println("删除键password:" + jedis.del("password"));System.out.println("判断键password是否存在:" + jedis.exists("password"));System.out.println("查看键username所存储的值的类型" + jedis.type("username"));System.out.println("随机返回key空间的一个" + jedis.randomKey());System.out.println("重命名key:" + jedis.rename("username","userName"));System.out.println("取出改后的userName:" + jedis


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部