Redis基础学习

4 篇文章 0 订阅

Redis概述

redis是典型的nosql数据库,nosql就是 非关系型数据库,和Java里的 Map<String,Object>相似,所以我们可以使用redis来做缓存

nosql的特点:

  1. 方便扩展,数据之间没有关系,很好扩展
  2. 大数据量高性能,Nosql的缓存记录是一种细粒度的缓存,性能高
  3. 数据类型多样,不需要事先设计数据库
  4. 传统的RDBMS(关系型数据库) 和Nosql

redis: Remote Dictionary Server

  • 内存存储,持久化(使用RDB和AOF(append only file)两种方式)

  • 效率高,可以用于高速缓存

redis有五大数据类型和三大特殊数据类型(geospatial,hyperloglog,bitmaps

redis是单线程的,使用了reactor模式的IO

为何redis是单线程?

redis是基于内存操作的,速度很快,所以redis的瓶颈不是CPU ,而是机器的内存和网络带宽,所以能使用单线程就使用单线程

redis使用单线程也很快?

  1. 运行速度是 CPU>内存>硬盘
  2. 多线程需要有CPU的上下文切换,不一定有单线程效率高
  3. redis将所有数据都放在内存中,所以使用单线程去操作,效率会是最高,用多线程时,CPU会有上下文切换,耗时较长。对于内存系统来说,如果没有上下文切换,效率就是最高的,多次读写都是在一个CPU上,所以redis使用单线程

命令:

启动: 去点击redis目录下的 redis-server 启动redis服务器,点击 redis-cli启动redis客户端来连接服务器

redis默认有16个数据库(0-15)默认使用0号数据库 ,我们可以使用 select index来切换数据库

  • select index 切换数据库
  • dbsize :获取当前数据库的 键值对 的个数
  • keys * 得到当前数据库的所有键值对
  • flushdb 清空当前数据库
  • flushall 清空所有数据库
  • move key index 把某个 键值对 移动到 index数据库中去,那么当前数据库的键值对就会消失
  • expire key seconds 设置过期时间
  • pexpire key milliseconds 设置过期时间,以毫秒为单位(后面设置的过期时间会覆盖前面设置的)
  • ttl key 查看还有多久过期,返回值是 秒
  • pttl key 查看还有多久过期 ,返回值是 毫秒
  • expireat key timestamp 设置过期时间,前面是设置的是剩余的存活时间,这个设置的是存活到某个时间
  • pexpireat key timestamp
  • time获取当前时间戳,可用于与上面 配置
  • type key 获取类型

五大数据类型:

String

  • set key value
  • append key value 当key为 null的时候相当于 set,不然就是追加在 key的value 后面
  • strlen key 获取字符串长度,这是在String的对象里有记录字符串长度的属性,所以时间复杂度为 O(1)
  • setnx key value set if not exist 不存在才设置,设置失败的话返回 0
  • mset key1 value1 key2 value2 ... multiple set ,批量设置
  • mget key1 key2 key3

List

list链表里的value值是可以重复的

  • lpush key value1 value2 value3 插入数据
  • lrange key start stop 取数据,下标从0开始,到stop结束(包括stop),然后stop为-1的时候是取出start 后面所有

在这里插入图片描述

  • rpop key 弹出链表尾值,链表中就会少一个值
  • lpop key ,弹出链表头的值

在这里插入图片描述

  • llen key 得到链表的长度
  • lrem key count value 在链表里面删除值为 value ,的元素,只删除count个,从链表头开始删 (为何是从链表头开始查,因为redis对链表的掌控都是使用 链表头的,所以遍历自然也是从链表头开始遍历,那么查到了就删,所以可以说是从链表头开始删)

在这里插入图片描述

  • ltrim key start end 把当前的链表切割成 list[start]–>list[end] 这部分
  • rpoplpush src dst 从src链表中使用 rpop取出一个值,使用lpush插入到dst链表中去
  • lset key index value 把链表中的index这个位置的元素改成 value,也就是根据索引修改值
  • linsert key before|after pivot value(pivot是中心,也就是要查找的值),(list的值可以重复,所以就是找到离链表头最近的那个进行操作,原理上面有说过)在这里插入图片描述

Set

list是有序的,set是无序的,所以前面list能使用索引进行操作,但是set就不可以

set是无序不重复的集合

  • sadd key value 插入
  • smembers key 得到所有的成员
  • sismember key value 判断set是否存在 value这个值
  • scard key 查询set的数量
  • srem key value删除set里的value
  • spop key 随机删除
  • smove src dst value 将src里的value移动到dst里去,dst可以不存在,移动的时候创建,src这个set就会丢失value
  • srandmember key count随机取count个元素
  • sdiff key1 key2取两个set的差集
  • sinter key1 key2取两个set的交集
  • sunion key1 key2 取两个set的并集

Hash

类似于Java里的Map

  • hset key field value ,只能一对一对地赋值
  • hmset key field1 value1 field2 value2 多对赋值
  • hget key field 取出hash集合里的field对应的value值
  • hmget key field1 field2 field3 一次性取多个值
  • hgetall key取出全部的 键值对
  • hkeys key取出所有键值对的 key
  • hvals key取出所有键值对的 value

Zset

按照score进行排序的set,可以叫做有序不重复集合

  • zadd key score1 member1 score2 member2 插入
  • zrange key start stop 查看值,stop可以是 -1
  • zrevrange key start stop 倒序查看
  • zrangebyscore key min max按照分值查看值,这里min和max的值可以是 -int(表示最小整数), +int(表示最大整数)
  • zrem key value 删除

三大特殊类型

geospatial

这个就是地图

  • geoadd key longitude latitude member 添加值,longitude指的是经度,latitude是纬度
  • geopos key value 查看
  • geodist key member1 member2 [unit] 根据两个元素的经纬度计算两地的距离,unit可以修改单位,默认是m,可以改成 km

hyperloglog

用于基数统计

基数 :每个重复的元素只计算一次

  • pfadd key element 插入
  • pfmerge dst src 将src合并到dst中去
  • pfcount key 计算基数

BitMap

类似于Map ,但是bitmap的值只能设置 0/1 ,所有只存在两种状态的结构都可以使用bitmaps

  • setbit key offset value设置
  • getbit key offset 查看

事务

redis事务: 一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行过程中会按照顺序执行

Redis会将一个事务中的所有命令序列化,然后按顺序执行。Redis不可能在一个Redis事务的执行过程中插入执行另一个客户端发出的请求。这样便能保证Redis将这些命令作为一个单独的隔离操作执行。

在一个Redis事务中,Redis要么执行其中的所有命令,要么什么都不执行。因此,Redis事务能够保证原子性

redis事务的特性: 一次性顺序性排他性

使用事务:

  1. 标记事务块的开始 multi
  2. 命令入队,redis会将命令逐个放入队列中
  3. 执行事务 exec ,在一个事务中执行所有先前放入队列的命令,返回值是一个数组,分别是每一条命令的返回值
  4. 丢弃命令队列 discard清除所有放入队列的命令

事务错误:

事务执行时会产生两种错误:

  • 一个命令可能会在被放入队列时失败。因此,事务有可能在调用EXEC命令之前就发生错误。例如,这个命令可能会有语法错误(参数的数量错误、命令名称错误,等等),或者可能会有某些临界条件(例如:如果使用maxmemory指令,为Redis服务器配置内存限制,那么就可能会有内存溢出条件)。
  • 在调用EXEC命令之后,事务中的某个命令可能会执行失败。例如,我们对某个键执行了错误类型的操作(例如,对一个字符串(String)类型的键执行列表(List)类型的操作)。

对于第一种,服务器会记住事务积累命令期间发生的错误。然后,Redis会拒绝执行这个事务,在运行EXEC命令之后,便会返回一个错误消息。最后,Redis会自动丢弃这个事务。

在这里插入图片描述

对于第二种,也就是在调用EXEC命令之后发生的事务错误,Redis不会进行任何特殊处理:在事务运行期间,即使某个命令运行失败,所有其他的命令也将会继续执行。

在这里插入图片描述

redis为何不支持回滚

只有当被调用的Redis命令有语法错误时,这条命令才会执行失败(在将这个命令放入事务队列期间,Redis能够发现此类问题),或者对某个键执行不符合其数据类型的操作:实际上,这就意味着只有程序错误才会导致Redis命令执行失败,这种错误很有可能在程序开发期间发现,一般很少在生产环境发现。
事务回滚并不能解决任何程序错误。例如,如果某个查询会将一个键的值递增2,而不是1,或者递增错误的键,那么事务回滚机制是没有办法解决这些程序问题的。请注意,没有人能解决程序员自己的错误,这种错误可能会导致Redis命令执行失败。正因为这些程序错误不大可能会进入生产环境,所以发Redis时选用更加简单和快速的方法,没有实现错误回滚的功能。

锁、监视器

  • 悲观锁 : 认为什么时候都会出问题,无论什么时候才会加锁
  • 乐观锁:很乐观,认为什么时候都不会出问题,所以不会上锁,更新数值的时候才判断在此期间是否有人修改过此数据 ,方法是使用版本 获取version---->更新的时候比较version

redis可以使用 CAS(检查再设置,compare and swap)实现乐观锁,用的是 watch 命令:

  1. 开启两个客户端 cli1 和 cli2
  2. 在 cli2 使用watch key给某个变量上锁,然后开启事务
  3. 在cli1 使用 set key 修改这个变量
  4. 在cli2的事务里get key 查看变量和 set key修改变量
  5. cli2的事务提交 exec,发现返回值为nil,也就是事务允许失败

在这里插入图片描述

我们在 watch key给这个key上锁,拿到一个version,我们上锁之后在事务执行期间在第二个客户端执行了set,修改了version,当我们事务去执行的时候就会发现version版本不同,执行失败。

要拿到最新的版本需要 unwatch–> watch

Java操作redis

jedis是redis官方推荐的Java连接开发工具

依赖:

<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
</dependency>

但是我们在使用spring boot的时候,依赖则是:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

spring-boot-starter-data-redis使用的是 lettuce的方式连接redis

  • jedis: 采用的是直连,多个线程操作时不安全的,如果想要避免不安全的,使用jedis pool连接池!像BIO模式
  • lettuce: 采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程数据了,更像NIO模式

使用:

  1. 导入spring-boot-starter-data-redis依赖
  2. 配置文件里配置 spring.redis.hostspring.redis.port
  3. 自动注入 RedisTemplate

在这里插入图片描述

查看里面的方法,可以发现几乎全部都是RedisSerializer类型,所以我们在向redis设置值的时候,所有对象都需要进行序列化,否则会报错

序列化方法:

  • 使用ObjectMapper类的writeValueAsString(Object value)
  • 对象实现 Serializable接口

对reids的操作方法:

  • 使用redis的opsforXXXXX().set()来进行设置值的操作
  • 使用opsForXXXXX().get() 来进行取值的操作

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值