Redis笔记

Redis

什么是nosql

not only SQL

不仅仅是SQL语句

是一个非关系型数据库

泛指非关系型数据库的 随之web2.0互联网的诞生 传统的关系型数据库很难对付web2.0时代

尤其是超大规模的高并发的社区 暴露出来很多的问题 nosql在现在大数据环境下发展迅速

Redis是最快的 而且使我们当下必须要找我的技术

很多非关系型用户的个人信息 社交网络 地理位置 这些数据类型的存储不需要固定的格式

不需要多月的操作就可以横向发展 Map<String,Object> 键值对控制

特点

解耦

1.方便扩展 数据之间没有关系 很好扩展

2.大数据量高性能(Redis一秒写8万次 读11万次 nosql的缓存记录集是细粒度的缓存 性能会比较高)

3.数据类型的多样性(不需要事先设计数据库 随取随用 如果数据量十分大的表 很多人无法设计的)

4.传统的RDBMS和nosql

传统的RDBMS
	-结构化组织
    -sql
    -数据和关系都存在单独的表中
    -操作数据定义语言
    -严格的一致性
    -基础的事务
    -.......
    
nosql:
    -不仅仅是数据库
    -没有固定的查询语言
    -键值对存储 列存储 文档存储 图形数据库
    -最终一致性
    -CAP定理和base(一定多活)  初级架构师 会这个
    -高性能高可用 高可扩展

redis四大类

kv键值对

  • 新浪:Redis

  • 美团:Redis+tair

  • 阿里,百度:Redis+memacache

文档数据库(bson格式和json一样)

  • MongoDB 掌握
    • 是一个基于分布式文件存储的数据库 c++编写 主要是处理大量的文档
    • 是一个介于关系型数据库和非关系型数据库之间的中间的产品.
    • 是非关系型数据库中最像关系型数据库的非关系型数据库

列存储数据库

  • HBASE
  • 分布式文件系统

图关系数据库

存储的不是图形存的是关系 比如:朋友 同时关系

Redis概念

远程字典服务 支持多种语言使用

免费开源 当下最热门的nosql技术之一 被称为结构化数据库

能干嘛

1.内存存储 持久化 内存中的数据是断电即失 所以说持久化很重要(RDB APF)

2.效率高 高速缓存

3.发布订阅系统

4.地图信息分析

5.定时器 计时器 (浏览量)

特性

1.多样的数据类型

2.持久化

3.集群

4.事务

基础命令

启动方式

1.打开Redis配置文件

2.启动 并设置端口号是6379

[root@izbp12nmkl044l6gs1yldoz bin]# redis-server ./zconfig/redis.conf 
[root@izbp12nmkl044l6gs1yldoz bin]# redis-cli -p 6379

命令

Redis默认有16个数据库 默认是第0个 各个数据库之间是不相同的 你在零号数据库存入数据在其他数据库是没有这个数据的

基础:

select

DBSIZE

set key value

get key =>value

keys *

127.0.0.1:6379> select 3 //切换数据库
OK
127.0.0.1:6379[3]> DBSIZE//查看数据库中数据条数
(integer) 0
127.0.0.1:6379[3]> set name zxh //往数据库里存入数据 键值对方式
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 1
127.0.0.1:6379[3]> select 7
OK
127.0.0.1:6379[7]> DBSIZE
(integer) 0
127.0.0.1:6379[7]> select 3
OK
127.0.0.1:6379[3]> get name //获取value值
"zxh"
127.0.0.1:6379[3]> keys * //查看当前数据库中所有的key
1) "name"

清空数据库

flushdb 清空当前的数据库中所有的数据

127.0.0.1:6379[3]> flushdb
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 0

FLUSHALL清空所有数据库中的数据

127.0.0.1:6379[3]> set name zxh
OK
127.0.0.1:6379[3]> select 0
OK
127.0.0.1:6379> DBSIZE
(integer) 0
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> DBSIZE
(integer) 0
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 0
Redis是单线程的

Redis是基于内存操作的 CPU不是Redis的瓶颈 Redis的瓶颈是和机器的内存的网络带宽决定的 既然可以使用单线程来实现 就用单线程了

为什么单线程还那么快?

Redis是将所有的数据全部放在内存中的 所有说 使用单线程去操作的效率就是最高的 多线程存在CPU的上下文切换 这个操作耗时很高。对于内存系统来说说 如果没有上下文切换效率就是最高的 多次读写都是发生在一个CPU下的,在内存情况好的情况下这个方案最佳

Redis-key

expire key time 设置当前的key的过期时间 单位为秒

ttl key 查看当前的key剩余的存活时间

ExISTS key 判断当前的key是否存在

move key 1 移除这个key

127.0.0.1:6379[3]> set name zxh
OK
127.0.0.1:6379[3]> set age 13
OK
127.0.0.1:6379[3]> exists name
(integer) 1
127.0.0.1:6379[3]> type name
string
127.0.0.1:6379[3]> move name 1
(integer) 1
127.0.0.1:6379[3]> keys *
1) "age"
127.0.0.1:6379[3]> expire age 10
(integer) 1
127.0.0.1:6379[3]> ttl age
(integer) 7
127.0.0.1:6379[3]> ttl age
(integer) 5
127.0.0.1:6379[3]> ttl age
(integer) 3
127.0.0.1:6379[3]> ttl age
(integer) -2
127.0.0.1:6379[3]> keys *
(empty array)

i++ i–方法

incr key

decr key

incrby key 10 key+10

decrby key 5 key-5

type key查看当前类型

获取字符串的长度 strlen key

追加字符串 append key “内容” 如果key不存在就新建

127.0.0.1:6379[3]> set amount 0
OK
127.0.0.1:6379[3]> get amount
"0"
127.0.0.1:6379[3]> incr amount
(integer) 1
127.0.0.1:6379[3]> get amount
"1"
127.0.0.1:6379[3]> decr amount
(integer) 0
127.0.0.1:6379[3]> incrby amount 10
(integer) 10
127.0.0.1:6379[3]> get amount
"10"
127.0.0.1:6379[3]> set name zxh
OK
127.0.0.1:6379[3]> strlen zxh
(integer) 0
127.0.0.1:6379[3]> strlen name
(integer) 3
127.0.0.1:6379[3]> append name ",hello"
(integer) 9
127.0.0.1:6379[3]> strlen name
(integer) 9
127.0.0.1:6379[3]> 

截取字符串 GETRANGE key head last

替换 setrange key 位置 字符

127.0.0.1:6379[3]> set name zxzxxzx
OK
127.0.0.1:6379[3]> getrange name 0 3
"zxzx"
127.0.0.1:6379[3]> setrange name 1 hhh
(integer) 7
127.0.0.1:6379[3]> get name
"zhhhxzx"

setex 设置一个临时的数据 存在时间

setnx 当这个key不存在时候才能设置 保存原有的数据不被改变

127.0.0.1:6379[3]> set name zxh
OK
127.0.0.1:6379[3]> setnx name hhh
(integer) 0
127.0.0.1:6379[3]> get name
"zxh"
127.0.0.1:6379[3]> setex age 10 10
OK
127.0.0.1:6379[3]> ttl age
(integer) 6
127.0.0.1:6379[3]> ttl age
(integer) 3
127.0.0.1:6379[3]> ttl age
(integer) 1
127.0.0.1:6379[3]> ttl age
(integer) -2
127.0.0.1:6379[3]> keys *
1) "name"

mset 批量创建值

mget 批量获取值

msetnx 注意原子性 如果创建的值不是同时成立 就全部失败

127.0.0.1:6379[3]> mset k1 v1 k2 v2
OK
127.0.0.1:6379[3]> mget k1 k2
1) "v1"
2) "v2"
127.0.0.1:6379[3]> msetnx k1 v3 k3 v3
(integer) 0
127.0.0.1:6379[3]> get k1
"v1"
127.0.0.1:6379[3]> get k3
(nil)

创建一个对象 set user:1{name:zxh,age:2} 设置一个user:1对象 值为json的字符串

这里的key是一个user:{id}:{filed} 如此设计在 Redis是可行的

127.0.0.1:6379[3]> mset user:1:name zxh user:1:age 12
OK
127.0.0.1:6379[3]> mget user:1:name user:1:age
1) "zxh"
2) "12"

getset 先get后set方法 常用与更新

127.0.0.1:6379[3]> getset db redis
(nil)
127.0.0.1:6379[3]> getset db java
"redis"
127.0.0.1:6379[3]> get db
"java"

list

命令与string的命令相似 大部分都是前面加一个L

127.0.0.1:6379> lpush list one 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
1) "three"
2) "two"
127.0.0.1:6379> rpush list zero #向右插入一个元素
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "zero"

lpop 移除list中第一个元素

rpop 移除最后一个元素

127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> rpop list
"zero"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"

lindex 通过下标找值

llen返回列表长度

移除指定值 lrem

127.0.0.1:6379> lindex list 1
"one"
127.0.0.1:6379> llen list
(integer) 2
127.0.0.1:6379> lpush list three four
(integer) 4
127.0.0.1:6379> llen list
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 four
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"

截取元素 reim

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> ltrim list 0 1
OK
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"

rpoplpush 移除元素再添加元素到另一个表里

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
127.0.0.1:6379> rpoplpush list mylist
"two"
127.0.0.1:6379> lrange mylist 0 -1
1) "two"
127.0.0.1:6379> lrange list 0 -1
1) "three"

lset将列表中指定下标的值替换为另外一个值 相当于更新操作

127.0.0.1:6379> lrange list 0 -1
1) "three"
127.0.0.1:6379> lset list 0 item
OK
127.0.0.1:6379> lrange list 0 -1
1) "item"

在指定的位置插入一个元素

127.0.0.1:6379> lrange list 0 -1
1) "item"
127.0.0.1:6379> linsert list before item pus
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "pus"
2) "item"

set 集合

基本命令:

127.0.0.1:6379> sadd myset hello world zxh
(integer) 3
127.0.0.1:6379> smembers myset
1) "zxh"
2) "hello"
3) "world"
127.0.0.1:6379> sismember myset hello #判断是否存在这个值 如果存在就返回1
(integer) 1
127.0.0.1:6379> sismember myset mmm
(integer) 0

scard 查询set中元素个数

srem 移除元素

srandmember 随机数

127.0.0.1:6379> scard myset
(integer) 3
127.0.0.1:6379> srem myset hello
(integer) 1
127.0.0.1:6379> smembers myset
1) "zxh"
2) "world"
127.0.0.1:6379> srandmember myset
"zxh"
127.0.0.1:6379> srandmember myset
"zxh"
127.0.0.1:6379> srandmember myset
"zxh"
127.0.0.1:6379> srandmember myset
"world"

spop 随机弹出一个元素

smove 移除指定元素到另一个set中

127.0.0.1:6379> spop myset
"zxh"
127.0.0.1:6379> smembers myset
1) "world"
127.0.0.1:6379> sadd myset new today
(integer) 2
127.0.0.1:6379> smembers myset
1) "new"
2) "today"
3) "world"
127.0.0.1:6379> smove myset myset2 new
(integer) 1
127.0.0.1:6379> smembers myset2
1) "new"
127.0.0.1:6379> smembers myset
1) "today"
2) "world"

数学集合:

差集 sdiff

交集 sinter

并集sunion

127.0.0.1:6379> sadd key1 a b c d
(integer) 4
127.0.0.1:6379> sadd key2 a b e f
(integer) 4
127.0.0.1:6379> sdiff
(error) ERR wrong number of arguments for 'sdiff' command
127.0.0.1:6379> sdiff key1 key2
1) "d"
2) "c"
127.0.0.1:6379> sinter key1 key2
1) "b"
2) "a"
127.0.0.1:6379> sunion key1 key2
1) "d"
2) "b"
3) "c"
4) "f"
5) "a"
6) "e"

hash表

底层是map集合

127.0.0.1:6379> hset myhash k1 v1 #创建键值对
(integer) 1
127.0.0.1:6379> hget myhash k1
"v1"
127.0.0.1:6379> hmset myhash k1 m1 k2 m2 k3 m3#创建多个键值对
OK
127.0.0.1:6379> hmget myhash k1 k2 k3#显示指定键值对们
1) "m1"
2) "m2"
3) "m3"
127.0.0.1:6379> hgetall myhash #显示所有键值对
1) "k1"
2) "m1"
3) "k2"
4) "m2"
5) "k3"
6) "m3"
127.0.0.1:6379> hdel myhash k1#移除指定键值对
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "k2"
2) "m2"
3) "k3"
4) "m3"
127.0.0.1:6379> hlen myhash#当前表的元素个数
(integer) 2
127.0.0.1:6379> hexists myhash k2#判断键是否存在
(integer) 1
127.0.0.1:6379> hexists myhash k1
(integer) 0
127.0.0.1:6379> hkeys myhash #显示所有的key
1) "k2"
2) "k3"
127.0.0.1:6379> hvals myhash #显示所有的vals
1) "m2"
2) "m3"

zset (有序集合)

在set的基础上添加了一个值

127.0.0.1:6379> zadd salary 2000 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 200 zhang
(integer) 1
127.0.0.1:6379> zadd salary 1000 hui
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf #按工资大小输出值
1) "zhang"
2) "hui"
3) "xiaohong"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "zhang"
2) "200"
3) "hui"
4) "1000"
5) "xiaohong"
6) "2000"
127.0.0.1:6379> zrange salary 0 -1 #显示所有的人
1) "zhang"
2) "hui"
3) "xiaohong"
127.0.0.1:6379> zrem salary hui#移除hui指定元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "zhang"
2) "xiaohong"
127.0.0.1:6379> zadd myset 1 hello 2 world 3 name
(integer) 3
127.0.0.1:6379> zcount myset 1 3 #获取区间的长度
(integer) 3
127.0.0.1:6379> zcount myset 1 2
(integer) 2

三大特殊类型

geospatial地理位置

geoadd:添加地理位置和地名 维度 精度

geodist:二地之间的距离 单位自己定义

geohash:不用

geopos: 查看

georadius:以给定的经纬度为中心 找出某一个半径内的元素

georadiusbymember:找出位于指定元素周围的其他元素

hypeloglog基数统计

常用与统计人数 数量上 存在大数据是可能有误差 传统的方式set保存用户id 然后统计元素很麻烦 我们的目的是计数不是保存id

pfadd 添加

pfcount 统计数

pfmerge 将二表中基数放到新表中

127.0.0.1:6379> pfadd key1 a s x c v d g h 
(integer) 1
127.0.0.1:6379> pfcount key1
(integer) 8
127.0.0.1:6379> pfadd key2 a b x d c e f
(integer) 1
127.0.0.1:6379> pfcount key2
(integer) 7
127.0.0.1:6379> pfmerge key3 key1 key2
OK
127.0.0.1:6379> pfcount key3
(integer) 11
bitmap位图场景

当你想统计的值只存在两种状态 就可以使用这个位图统计

比如:上班打卡 活不活跃 在不在线等等

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> getbit sign 1
(integer) 0
127.0.0.1:6379> getbit sign 0
(integer) 1
127.0.0.1:6379> bitcount sign
(integer) 2

事务

Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中 会按照顺序执行,一次性 顺序性 排他性 执行一些列命令

------------队列 set set set 执行----------

Redis事务没有隔离级别的概念

所有的命令在事务中 并没有直接被执行 只有发起执行命令的时候 才会执行 exec

Redis只有单条命令保存原子性,但是事务不保证原子性

Redis事务:

​ 开启事务 multi

​ 命令入队 …

​ 执行事务 exec

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> get k1
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v1"
4) OK

放弃事务 discard 当你数据添加有问题 可以放弃这次事务提交

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get k4
(nil)

事务提交或者放弃之后 需要重新开始事务 因为Redis事务提交或者放弃等于结束事务

两种错误:

编译型异常:代码有问题 命令有错 事务不会执行

运行时异常:比如逻辑错误 1/0 逻辑错误不管继续执行其他命令

悲观锁和乐观锁

悲观锁:

  • 顾名思义 很悲观 认为什么时候都会出问题 所以无论做什么都加锁

乐观锁:

  • 很乐观 认为什么都不会出问题 所以不上锁 更新数据时候去判断一下再此期间是否有人改动数据
  • 获取version
  • 更新时比较version是否前后一致

Redis检测模式:watch

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> 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

当你的数据执行失败时候 很大可能是因为你锁住的数据发生了改变 导致的

这个时候 需要unwatch 放弃锁 然后再次watch 就可以了

jedis

我们使用java操作Redis

什么是jedis?

是Redis官方推荐的java连接开发工具 使用java操作Redis中间件 如果你要使用java操作Redis 那么必须对jedis熟悉

测试:

​ 1.导入依赖

​ 2.编码测试

package com.zxh;

import redis.clients.jedis.Jedis;

public class TestPing {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1",6379);
        System.out.println(jedis.ping());
    }
}

事务:

package com.zxh;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class TestPing {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1",6379);
        System.out.println(jedis.ping());
        Transaction multi = jedis.multi();
        try {
        multi.set("user1","hello");
        multi.set("user2","world");
        multi.exec();
        }catch (Exception e){
            multi.discard();
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();
        }
    }
}

配置文件中常用的一些配置

常用配置意义
bind 127.0.0.1绑定的ip
protected-mode yes保护模式
port 6379端口设置
daemonize yes守护进程的方式运行 默认是no 需要开启
pidfile /var/run/redis_6379.pid后台方式运行需要指定一个pid文件
loglevel notice日志
logfile “”日志的文件名
database 16数据库的数量 默认是16个
always-show-logo yes是否显示log
save 900 1 / 300 10 /60 1000快照 判断什么时候进行持久化操作
stop-writes-on-bgsave-error yes持久化出错时 是否还要继续工作
rdbcompression yes是否压缩rdb文件 需要消耗CPU资源
rdbchecksum yes保存rdb文件时 进行错误的检测校验
dir ./rdb文件保存的目录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值