Redis
官方解释:Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作**数据库、缓存和消息中间件**。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
一 、Redis为什么是单线程的?
解释:明白Redis是很快的,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,就可以使用单线程来实现!
Redis是C语言写的,
Redis为什么是单线程还这么快?
1. 高性能的服务器不一定是多线程的
2. 多线程不一定比单线程效率高!
核心解释: redis是将所有的数据全部放在在内存中的,所以说使用单线程去操作效率就是最高的,多线程,对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳方案!**
二 、Redis-Key
指令:
注意:move指令是移动key到另一个数据库
bash
keys * # 查看所有的key
EXISTS(exists) name # 判断当前的key是否存在
move name 1 # 把当前的key移动到1数据库中
EXPIPE(expipe) name 10 # 设置key的过期时间, 单位是秒
ttl name # 查看当前key的剩余时间
set name zhangdg #
type name # 查看当前key的类型 String
1.String
set key1 v1 # 设置值
get key1 # 获得值
keys * # 获得所有的key
EXISTS key1 # 判断某一个key是否存在
APPEND key1 ”hello“ # 追加字符串,如果当前key不存在,就相当于setkey
STRLEN key1 # 获取字符串的长度
set views 0
incr # 自动加一
decr # 自动减一
INCRBY views 10 # 自动加10
DECRBY views 10 # 自动减10
# 字符串范围 rang
set key1 "hello, zhangdg" # 设置key1的值
get key1
GETRANGE key1 0 3 # 截取字符串【0,3】
GETRANGE key1 0 -1 # 获取全部的字符串 和get key 是一样的
SETERANGE key2 1 xx # 替换指定位置的字符串!
get key2
setex #如果当前值存在,设置过期时间
setnx #如果当前值不存在,设置 (在分布式锁中会常常使用!)
setex key3 30 # 设置key3的值为hello,30秒自动过期
ttl key3 # 查看剩余时间
setnx mykey "redis" # 如果mykey不存在,创建
setnx mykey "MongoDB" # 如果mykey存在,创建失败!
mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
key *
mget k1 k2 k3 # 同时获取多个值
msetnx k1 v1 k4 v4 # mysetnx 是一个原子性的操作,要么一起成功,要么一起失败!
# 对象
set user: 1 {name:zhangsan, age:3} #设置一个user:1 对象 , 值为 json字符来保存一个对象!
# 这里是一个巧妙的设计: user:{filed} , 如此设计在Redis中是完全ok了!
# getset
getset db redis # 先get后set ,如果不存在值,则返回nil
get db
getset db mongodb # 如果存在值,获取原来的值,病设置新的值
数据结构是相同的!
String类似的使用场景:value除了是我吗的字符串还可以是我们的数字!
- 计数器
- 统计多单位的数量 uid:95256449 follow 0
- 粉丝数
- 对象缓存存储
事务
Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
- 一次性
- 顺序性
- 排他性
- 执行一些列的命令
# 队列 set set set 执行
Redis事务没有隔离级别的概念!所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!
执行命令:Exec
Redis单条命令式保存原子性的,但是事务不保证原子性!
Redis的事务:
- 开启事务(multi)
- 命令入队()
- 执行事务(exec)
# 正常执行事务!
multi # 开启事务
# 命令入队
set k1 v1
set k2 v2
get k2
set k3 v3
exec # 执行事务
DISCARD # 取消事务
编译型异常(代码有问题,命令有错),事务中的所有命令都不会被执行
运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
乐观锁
监控! Watch(面试常问!)
乐观锁其实用一句话来形容其作用就是:当要更新一条记录的时候,希望这条记录没有被别人更新,从而实现线程安全的数据更新。
获取Version,跟心的时候比较Version。
Redis监视测试 —— 正常执行成功!
set money 100
ok
set out 0
ok
watch money # 监视 money 对象
ok
multi # 事务正常结束,数据期间没有发生变动,这个时候就正常执行成功
ok
money 20
QUEUED
INCRBY out 20
QUEUED
exec
(integer)80
(integer)20
测试多线程修改值,使用watch可以当做redis的乐观锁操作!
watich money # 监视money
multi
DECRBY money 10
INCRBY out 10
exec # 执行之前,另外一个线程,修改了我们的值,这个时候,就会导致事务执行失败!
nil
unwatch # 如果发现事务执行失败,就先解锁
watch money # 获取最新的值,再次监视, select version
DECRBY money 10
INCRBY out 10
exec # 比对监视的值是否发生了变化,如果没变化,那么可以执行成功,如果变化了,执行失败!
30
如果修改失败,获取最新的值就可以了!
Jedis
我们要使用java来操作Redis
什么是Jedis:是Redis官方推荐的java连接开发工具!使用java操作Redis中间件!如果你要用java操作redis,那么一定更要对jedis十分的熟悉!
测试
1.导数包:
<!-- 导入jedis的包-->
<dependencies>
<dependency>
<groupId>org.clojars.aperiodic</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.80</version>
</dependency>
</dependencies>
2.编码测试:
- 连接数据库
- 操作命令
- 断开连接!