Redis概述和基础
Redis
1、NoSQL
NoSQL = Not Only SQL(不僅僅是SQL)
泛指非關(guān)系型數(shù)據(jù)庫(kù)的,隨著web2.0互聯(lián)網(wǎng)的誕生!傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)很難對(duì)付web2.0時(shí)代!尤其是超大規(guī)模的高并發(fā)的社區(qū)!暴露出來(lái)很多難以克服的問(wèn)題,NoSQL在當(dāng)今大數(shù)據(jù)環(huán)境下發(fā)展的十分迅速,Redis是發(fā)展最快的,也是當(dāng)下我們必須掌握的技術(shù)。
很多的數(shù)據(jù)類型用戶的個(gè)人信息,社交網(wǎng)絡(luò),地理位置。這些數(shù)據(jù)類型的存儲(chǔ)不需要一個(gè)固定的格式!不需要多月的操作就可以橫向擴(kuò)展的!
NoSQL特點(diǎn)
1、方便擴(kuò)展(數(shù)據(jù)之間沒有關(guān)系,很好擴(kuò)展!)
2、大數(shù)據(jù)量高性能(Redis1秒寫8萬(wàn)次,讀11萬(wàn)次,NoSQL的緩存記錄級(jí),是一種細(xì)粒度的緩存,性能會(huì)比較高!)
3、數(shù)據(jù)類型是多樣型的。(不需要事先設(shè)計(jì)數(shù)據(jù)庫(kù)!隨取隨用!)
4、傳統(tǒng)RDBMS和NoSQL
傳統(tǒng)RDBMS
- 結(jié)構(gòu)化組織
- SQL
- 數(shù)據(jù)和關(guān)系都存在單獨(dú)的表中
- 數(shù)據(jù)操作,數(shù)據(jù)定義語(yǔ)言
- 嚴(yán)格的一致性
- 基礎(chǔ)的事務(wù)
- ......
NoSQL
- 不僅僅是數(shù)據(jù)
- 沒有固定的查詢語(yǔ)言
- 鍵值對(duì)存儲(chǔ),列存儲(chǔ),文檔存儲(chǔ),圖形數(shù)據(jù)庫(kù)
- 最終一致性
- CAP定理和BASE(異地多活)
- 高性能,高可用,高可擴(kuò)
- ......
2、NoSQL的四大分類
KV鍵值對(duì)
- Redis
文檔型數(shù)據(jù)庫(kù)
- MongoDB:是一個(gè)基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),主要用來(lái)處理大量的文檔
- MongoDB是一個(gè)介于關(guān)系型數(shù)據(jù)庫(kù)和非關(guān)系型數(shù)據(jù)庫(kù)數(shù)據(jù)中中間的產(chǎn)物,MongoDB是非關(guān)系型數(shù)據(jù)庫(kù)中功能最豐富,最像關(guān)系型數(shù)據(jù)庫(kù)的。
列存儲(chǔ)數(shù)據(jù)庫(kù)
- HBase
- 分布式文件系統(tǒng)
圖關(guān)系數(shù)據(jù)庫(kù)
- ? Neo4j,InfoGrid
3、Redis入門
概述
Redis是什么?
Redis(Remote Dictionary Server),即遠(yuǎn)程字典服務(wù)!
Redis會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了master-slave(主從)同步。
Redis能干嘛?
1、內(nèi)存存儲(chǔ)、持久化,內(nèi)存中是斷電即失,所以說(shuō)持久化很重要(rdb、aof)
2、效率高,可以用于高速緩存
3、發(fā)布訂閱系統(tǒng)
4、地圖信息分析
5、計(jì)數(shù)器(瀏覽量!)
6、…
特性
1、多樣的數(shù)據(jù)類型
2、持久化
3、集群
4、事務(wù)
…
測(cè)試性能
redis-benchmark是一個(gè)壓力測(cè)試工具
官方自帶的性能測(cè)試工具
redis-benchmark命令參數(shù)
簡(jiǎn)單測(cè)試:
# 測(cè)試:100個(gè)并發(fā)連接 100000請(qǐng)求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
如何查看這些分析呢?
基礎(chǔ)知識(shí)
redis默認(rèn)數(shù)據(jù)庫(kù)有16個(gè)數(shù)據(jù)庫(kù)
默認(rèn)使用的是第0個(gè)
可以使用select進(jìn)行切換
127.0.0.1:6379> select 3 #切換數(shù)據(jù)庫(kù)
OK
127.0.0.1:6379[3]> dbsize #查看數(shù)據(jù)庫(kù)大小
(integer) 0
127.0.0.1:6379> set name khazix #設(shè)置key-value
OK
127.0.0.1:6379> get name #獲取key響應(yīng)的value
"khazix"
127.0.0.1:6379> keys * #查看所有的key
1) "name"
2) "myhash"
3) "mylist"
4) "key:__rand_int__"
5) "counter:__rand_int__"
127.0.0.1:6379> dbsize
(integer) 5
127.0.0.1:6379> flushall # 清空所有數(shù)據(jù)庫(kù)內(nèi)容
OK
127.0.0.1:6379> flushdb # 清空當(dāng)前數(shù)據(jù)庫(kù)內(nèi)容
OK
127.0.0.1:6379> dbsize
(integer) 0
Redis是單線程的
Redis是很快的,是基于內(nèi)存操作,CPU不是Redis性能瓶頸,Redis的瓶頸是根據(jù)機(jī)器的內(nèi)存和網(wǎng)絡(luò)帶寬,既然可以使用單線程來(lái)實(shí)現(xiàn),就使用單線程了!所以就使用了單線程了!
Redis為什么單線程那么快?
Redis是C語(yǔ)言寫的,官方提供的數(shù)據(jù)為100000——的QPS,完全不比同樣是使用key-value的Memecache差。
核心:Redis是將所有的數(shù)據(jù)放在內(nèi)存中的,所以使用單線程去操作效率就是最高的,多線程CPU上下文會(huì)切換(耗時(shí)的操作),對(duì)于內(nèi)存系統(tǒng)來(lái)說(shuō),如果沒有上下文切換效率就是最高的。多次讀寫都是在一個(gè)CPU上的,在內(nèi)存情況下,這個(gè)就是最佳的方案!
1、誤區(qū)1:高性能的服務(wù)器不一定是多線程的。
2、誤區(qū)2:多線程不一定比單線程效率高
4、五大數(shù)據(jù)類型
Redis是一個(gè)開源的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),它可以用作數(shù)據(jù)庫(kù)、緩存和消息中間件MQ。它支持多種類型的數(shù)據(jù)結(jié)構(gòu),如字符串(Strings),散列(hashes),列表(lists),集合(set),有序集合(sorted sets)與范圍查詢,bitmaps,hyperloglogs和地理空間(geospatial)索引半徑查詢。Redis內(nèi)置了復(fù)制(replication),LUA腳本(Lua scripting),LRU驅(qū)動(dòng)事件(LRU eviction),事務(wù)(transactions)和不同級(jí)別的磁盤持久化(persistence),并通過(guò)Redis哨兵(Sentinel)和自動(dòng)分區(qū)(Cluster)提供高可用性(high avaliability)。
Redis-Key
127.0.0.1:6379> set name khazix
OK
127.0.0.1:6379> set age 20
OK
127.0.0.1:6379> exists name #判斷當(dāng)前的key是否存在
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> move name 2 #移除當(dāng)前的key
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> set name khazix
OK
127.0.0.1:6379> expire name 10 # 設(shè)置過(guò)期時(shí)間,單位為秒
(integer) 1
127.0.0.1:6379> ttl name #查看當(dāng)前key的剩余時(shí)間
(integer) 7
127.0.0.1:6379> ttl name
(integer) 5
127.0.0.1:6379> ttl name
(integer) 4
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> type age #查看當(dāng)前key的類型
string
String(字符串)
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> append key1 "hello" #追加字符串,如果當(dāng)前key不存在就相當(dāng)于添加了一個(gè)key
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> strlen key1 #獲得當(dāng)前key對(duì)應(yīng)值的長(zhǎng)度
(integer) 7
127.0.0.1:6379> append key1 ",khazix"
(integer) 14
127.0.0.1:6379> get key1
"v1hello,khazix"******************************************************
127.0.0.1:6379> set views 0 #設(shè)置訪問(wèn)量
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #訪問(wèn)量自增1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> decr views #訪問(wèn)量自減1
(integer) 1
### 設(shè)置步長(zhǎng)
127.0.0.1:6379> incrby views 5 #訪問(wèn)量自增5
(integer) 6
127.0.0.1:6379> decrby views 5 #訪問(wèn)量自減5
(integer) 1
******************************************************
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set key1 "hello,khazix"
OK
127.0.0.1:6379> getrange key1 0 4 #截取字符串[0,3]
"hello"
127.0.0.1:6379> getrange key1 0 -1 #獲取全部的字符串
"hello,khazix"127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> setrange key2 1 xx #替換指定位置開始的字符串
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
*****************************************************
127.0.0.1:6379> setex key3 30 "hello" #設(shè)置過(guò)期時(shí)間
OK
127.0.0.1:6379> ttl key3
(integer) 22
127.0.0.1:6379> setnx mykey "redis" #不存在再設(shè)置(在分布式鎖中會(huì)常常使用)
(integer) 1
127.0.0.1:6379> setnx mykey "MongoDB" #如果mykey存在,創(chuàng)建失敗
(integer) 0
127.0.0.1:6379> keys *
1) "key1"
2) "mykey"
3) "key2"
*****************************************************
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同時(shí)設(shè)置多個(gè)值
OK
127.0.0.1:6379> mget k1 k2 k3 #同時(shí)獲取多個(gè)值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #已經(jīng)存在k1,創(chuàng)建失敗。msetnx是一個(gè)原子性的操作,要么一起成功,要么一起失敗
(integer) 0
127.0.0.1:6379> get k4
(nil)
*****************************************************
# 對(duì)象
set user:1 {name:zhangsan,age:3} # 設(shè)置一個(gè)user:1對(duì)象 值為json字符來(lái)保存一個(gè)對(duì)象!# user:{id}:{field}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 23
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "23"
*****************************************************
127.0.0.1:6379> getset db redis # 如果不存在值,則返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb # 如果存在值,獲取原來(lái)的值,并設(shè)置原來(lái)的值
"redis"
127.0.0.1:6379> get db
"mongodb"
String類似的使用場(chǎng)景:除了是我們的字符串還可以是我們的數(shù)字!
- 計(jì)數(shù)器
- 統(tǒng)計(jì)多單位的數(shù)量
- 粉絲數(shù)
- 對(duì)象緩存存儲(chǔ)
List(列表)
基本的數(shù)據(jù)類型,列表
在redis里面,我們可以把list變成棧、隊(duì)列、阻塞隊(duì)列。
127.0.0.1:6379> lpush list one # 將一個(gè)值或者多個(gè)值放入列表的頭部(左)
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 獲取list中的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1 # 通過(guò)區(qū)間獲取具體的值
1) "three"
2) "two"
127.0.0.1:6379> rpush list right # 將一個(gè)值或者多個(gè)值放入列表的尾部(右)
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
*****************************************************
127.0.0.1:6379> Lpop list # 移除list的第一個(gè)元素
"three"
127.0.0.1:6379> Rpop list # 移除list的最后一個(gè)元素
"right"
127.0.0.1:6379> Lrange list 0 -1
1) "two"
2) "one"
*****************************************************
127.0.0.1:6379> Lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 0 # 通過(guò)下標(biāo)獲取list中的值
"two"
127.0.0.1:6379> lindex list 1
"one"
*****************************************************
127.0.0.1:6379> Lpush list one
(integer) 1
127.0.0.1:6379> Lpush list two
(integer) 2
127.0.0.1:6379> Lpush list three
(integer) 3
127.0.0.1:6379> Llen list # 獲取列表的長(zhǎng)度
(integer) 3
*****************************************************
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "four"
3) "three"
4) "two"
5) "one"
127.0.0.1:6379> lrem list 2 four # 移除list集合中指定個(gè)數(shù)的value
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
*****************************************************
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> Rpush mylist "hello"
(integer) 1
127.0.0.1:6379> Rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> Rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> Rpush mylist "hello3"
(integer) 4
127.0.0.1:6379> ltrim mylist 1 2 # 通過(guò)下標(biāo)截取指定的長(zhǎng)度,這個(gè)list已經(jīng)改變,截?cái)嗔酥皇O陆厝〉脑?/span>
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
*****************************************************
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> rpush list "hello"
(integer) 1
127.0.0.1:6379> rpush list "hello1"
(integer) 2
127.0.0.1:6379> rpush list "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush list otherlist # 移除列表的最后一個(gè)元素,將它移動(dòng)到新的列表中!
"hello2"
127.0.0.1:6379> keys *
1) "list"
2) "otherlist"
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "hello1"
127.0.0.1:6379> lrange otherlist 0 -1
1) "hello2"
*****************************************************
127.0.0.1:6379> exists mylist # 判斷這個(gè)列表是否存在
(integer) 0
127.0.0.1:6379> lpush mylist value1
(integer) 1
127.0.0.1:6379> lrange mylist 0 0
1) "value1"
127.0.0.1:6379> lset mylist 0 item # 將list中指定下標(biāo)的值替換為另外一個(gè)值,更新操作
OK
127.0.0.1:6379> lrange mylist 0 0
1) "item"
*****************************************************
127.0.0.1:6379> flushdb
OK
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> linsert list before "world" "other" # 將某一個(gè)具體的value插入到列表中某個(gè)元素的前面或者后面
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> linsert list after "world" "new"
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"
小結(jié)
- 他實(shí)際上是一個(gè)鏈表,before Node after,left,right都可以插入值
- 如果key不存在,創(chuàng)建新的鏈表
- 如果key存在,新增內(nèi)容
- 如果移除了所有值,空鏈表,也代表不存在
- 在兩邊插入或者值改動(dòng),效率最高!中間元素,相對(duì)來(lái)說(shuō)效率會(huì)低一點(diǎn)~
Set(集合)
set中的值是不能重復(fù)的!
127.0.0.1:6379> sadd myset "hello" # set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd myset "khazix"
(integer) 1
127.0.0.1:6379> smembers myset # 查看指定set的所有值
1) "khazix"
2) "hello"
127.0.0.1:6379> sismember myset hello # 判斷某一個(gè)值是不是在set集合中
(integer) 1
127.0.0.1:6379> sismember myset world
(integer) 0
127.0.0.1:6379> scard myset # 獲取set集合中的內(nèi)容元素個(gè)數(shù)!
(integer) 2
*****************************************************
127.0.0.1:6379> srem myset "hello" # 移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> smembers myset
1) "khazix2"
2) "khazix"
127.0.0.1:6379> scard myset
(integer) 2
*****************************************************
set 無(wú)序不重復(fù)集合 抽取隨機(jī)值
127.0.0.1:6379> srandmember myset #隨機(jī)抽選出一個(gè)元素
"khazix"
127.0.0.1:6379> srandmember myset
"khazix2"
127.0.0.1:6379> srandmember myset
"khazix"
127.0.0.1:6379> srandmember myset
"khazix2"
127.0.0.1:6379> srandmember myset
"khazix"
127.0.0.1:6379> srandmember myset
"khazix"
127.0.0.1:6379> srandmember myset
"khazix2"
127.0.0.1:6379> srandmember myset
"khazix"
127.0.0.1:6379> srandmember myset 2 # 隨機(jī)抽選出指定個(gè)數(shù)元素
1) "khazix2"
2) "khazix"
127.0.0.1:6379> srandmember myset 10 # 當(dāng)set集合中的元素個(gè)數(shù)少于指定數(shù)量時(shí)顯示全部
1) "khazix2"
2) "khazix"
*****************************************************
127.0.0.1:6379> smembers myset
1) "khazix2"
2) "khazix"
127.0.0.1:6379> spop myset # 隨機(jī)刪除一些set集合中的元素
"khazix"
127.0.0.1:6379> smembers myset
1) "khazix2
*****************************************************
127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset "world"
(integer) 1
127.0.0.1:6379> sadd myset "khazix"
(integer) 1
127.0.0.1:6379> sadd myset2 "set2"
(integer) 1
127.0.0.1:6379> smove myset myset2 "khazix" # 將一個(gè)指定的值移動(dòng)到另外一個(gè)set集合
(integer) 1
127.0.0.1:6379> smembers myset
1) "world"
2) "hello"
127.0.0.1:6379> smembers myset2
1) "set2"
2) "khazix"
*****************************************************
微博、B站等,共同關(guān)注!(使用到了并集)
數(shù)字集合類:- 差集- 交集- 并集127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> smembers key2
1) "e"
2) "c"
3) "d"
127.0.0.1:6379> sdiff key1 key2 # key1集合中和key2集合中不同的元素
1) "b"
2) "a"
127.0.0.1:6379> sinter key1 key2 # key1集合中和key2集合中相同的元素
1) "c"
127.0.0.1:6379> sunion key1 key2 # key1集合中和key2集合中相交的元素
1) "b"
2) "a"
3) "c"
4) "e"
5) "d"
微博,A用戶將所有關(guān)注的人放在一個(gè)set集合中!將它的粉絲也放在一個(gè)集合中!
共同關(guān)注,共同愛好,二度好友,推薦好友!(六度分割理論)
Hash(哈希)
Map集合,key-Map,這個(gè)值是一個(gè)map集合。本質(zhì)和String類型沒有太大的區(qū)別,還是一個(gè)簡(jiǎn)單的key-value!
set myhash field value
127.0.0.1:6379> hset myhash field1 khazix #set一個(gè)具體的key-value
(integer) 1
127.0.0.1:6379> hget myhash field1 # 獲取一個(gè)字段值
"khazix"
127.0.0.1:6379> hmset myhash field1 hello field world # set多個(gè)key-value
OK
127.0.0.1:6379> hmget myhash field1 field # 獲取多個(gè)字段值
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash #獲取全部的數(shù)據(jù)
1) "field1"
2) "hello"
3) "field"
4) "world"
127.0.0.1:6379> hdel myhash field1 # 刪除hash指定key字段!對(duì)應(yīng)的value值也就消失了!
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field"
2) "world"
*****************************************************
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
127.0.0.1:6379> hlen myhash #獲取hash表的字段數(shù)量
(integer) 2
127.0.0.1:6379> hexists myhash field1 #判斷hash中指定字段是否存在
(integer) 1
127.0.0.1:6379> hexists myhash field3
(integer) 0
*****************************************************
127.0.0.1:6379> hkeys myhash # 只獲得所有field
1) "field1"
2) "field2"
127.0.0.1:6379> hvals myhash # 只獲得所有value
1) "hello"
2) "world"
*****************************************************
127.0.0.1:6379> hset myhash field3 5 # 自增
(integer) 1
127.0.0.1:6379> hincrby myhash field3 2
(integer) 7
127.0.0.1:6379> hincrby myhash field3 -1
(integer) 6
*****************************************************
127.0.0.1:6379> hsetnx myhash field4 hello # 如果不存在則可用設(shè)置
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 world # 如果存在則不能設(shè)置
(integer) 0
類似使用場(chǎng)景:
? hash變更的數(shù)據(jù) user name age,尤其是用戶信息之類的,經(jīng)常變動(dòng)的信息!hash更適合于對(duì)象的存儲(chǔ),String更加適合字符串存儲(chǔ)!
Zset(有序集合)
在set的基礎(chǔ)上,增加了一個(gè)值
127.0.0.1:6379> zadd myset 1 one # 添加一個(gè)值
(integer) 1
127.0.0.1:6379> zadd myset 2 two
(integer) 1
127.0.0.1:6379> zadd myset 3 three
(integer) 1
127.0.0.1:6379> zadd myset 4 four 5 five #添加多個(gè)值
(integer) 2
*****************************************************
排序如何實(shí)現(xiàn)?
127.0.0.1:6379> zadd salary 2500 zwq
(integer) 1
127.0.0.1:6379> zadd salary 3000 syq
(integer) 1
127.0.0.1:6379> zadd salary 5000 zxd
(integer) 1
127.0.0.1:6379> zadd salary 500 xjj
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf # 排序
1) "xjj"
2) "zwq"
3) "syq"
4) "zxd"
127.0.0.1:6379> zrevrange salary 0 -1 # 倒序
1) "zxd"
2) "syq"
3) "zwq"
4) "xjj"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #帶數(shù)據(jù)排序
1) "xjj"
2) "500"
3) "zwq"
4) "2500"
5) "syq"
6) "3000"
7) "zxd"
8) "5000"
127.0.0.1:6379> zrangebyscore salary -inf 3000 withscores #顯示工資小于等于3000的員工
1) "xjj"
2) "500"
3) "zwq"
4) "2500"
5) "syq"
6) "3000
*****************************************************
移除rem中的元素
127.0.0.1:6379> zrange salary 0 -1
1) "xjj"
2) "zwq"
3) "syq"
4) "zxd"
127.0.0.1:6379> zrem salary xjj # 移除有序集合中的指定集合
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "zwq"
2) "syq"
3) "zxd"
127.0.0.1:6379> zcard salary # 獲取有序集合中的個(gè)數(shù)
(integer) 3
*****************************************************
127.0.0.1:6379> zadd myset 1 hello
(integer) 1
127.0.0.1:6379> zadd myset 2 world 3 khazix
(integer) 2
127.0.0.1:6379> zcount myset 1 2 # 獲取指定區(qū)間間的成員數(shù)量
(integer) 2
127.0.0.1:6379> zcount myset 1 3
(integer) 3
更多API查看官方文檔
案例思路:set 排序 存儲(chǔ)班級(jí)成績(jī)表,工資表排序
普通消息 1 ,重要消息 2 。帶權(quán)重進(jìn)行判斷
排行榜應(yīng)用實(shí)現(xiàn),取TOP N實(shí)現(xiàn)
5、三種特殊數(shù)據(jù)類型
geospatial地理位置
Redis的Geo在Redis3.2版本就推出了!這個(gè)功能可以推算地理位置的信息,兩地之間的距離,方圓幾里的人!
可以查詢一些測(cè)試數(shù)據(jù): http://www.jsons.cn/lngcodeinfo
getadd
# getadd 添加地理位置
# 規(guī)則: 兩極無(wú)法直接添加,我們一般會(huì)下載城市數(shù)據(jù),直接通過(guò)java程序一次性導(dǎo)入
# 參數(shù) key 值(緯度)(精度)
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 114.05 22.52 shenzhen
(integer) 1
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2
geopos
127.0.0.1:6379> geopos china:city beijing # 獲取指定的城市的經(jīng)度和緯度
1) 1) "116.39999896287918091"2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city beijing chongqing
1) 1) "116.39999896287918091"2) "39.90000009167092543"
2) 1) "106.49999767541885376"2) "29.52999957900659211"
127.0.0.1:6379> geopos china:city beijin
geodist
兩人之間的距離!
單位:
- m表示單位為米
- km表示單位為千米
- mi表示單位為英里
- ft表示單位為英尺
127.0.0.1:6379> geodist china:city beijing shanghai # 查看上海到北京的距離,默認(rèn)單位為m
"1067378.7564"
127.0.0.1:6379> geodist china:city beijing shanghai km # 查看上海到北京的直線距離
"1067.3788"
127.0.0.1:6379> geodist china:city beijing hangzhou km # 查看杭州到北京的直線距離
"1127.3378"
georadius
我附近的人(獲得所有附近的人的地址,定位),通過(guò)半徑來(lái)查詢
獲得指定數(shù)量的人
所有的數(shù)據(jù)應(yīng)該都錄入:china:city,才會(huì)更加準(zhǔn)確
127.0.0.1:6379> georadius china:city 110 30 1000 km # 以100,30這個(gè)經(jīng)緯度為中心,尋找方圓1000km內(nèi)的城市
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km
1) "chongqing"
2) "xian"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist # 顯示到中心的距離
1) 1) "chongqing"2) "341.9374"
2) 1) "xian"2) "483.8340"127.0.0.1:6379> georadius china:city 110 30 500 km withcoord # 顯示他人的定位信息
1) 1) "chongqing"2) 1) "106.49999767541885376"2) "29.52999957900659211"
2) 1) "xian"2) 1) "108.96000176668167114"2) "34.25999964418929977"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 2 # 篩選出指定的結(jié)果
1) 1) "chongqing"2) "341.9374"3) 1) "106.49999767541885376"2) "29.52999957900659211"
2) 1) "xian"2) "483.8340"3) 1) "108.96000176668167114"2) "34.25999964418929977"
georadiusbymember
# 找出位于指定元素周圍的其他元素
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km
1) "beijing"
2) "xian"
geohash
該命令將返回11個(gè)字符的Geohash字符串
# 將二維的經(jīng)緯度轉(zhuǎn)換為一維的字符串
127.0.0.1:6379> geohash china:city beijing chongqing
1) "wx4fbxxfke0"
2) "wm5xzrybty0"
geo底層的實(shí)現(xiàn)原理其實(shí)就是Zset!我們可以使用Zset命令來(lái)操作geo
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city beijing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
Hyperloglog
簡(jiǎn)介
Redis2.8.9版本就更新了Hyperloglog數(shù)據(jù)結(jié)構(gòu)!
Redis Hyperloglog 基數(shù)統(tǒng)計(jì)的算法
優(yōu)點(diǎn):占用的內(nèi)存是固定的,2^64不同的元素的技術(shù),只需要廢12KB內(nèi)存!如果要從內(nèi)存角度來(lái)比較的話Hyperloglog首選!
網(wǎng)頁(yè)的UV(一個(gè)人訪問(wèn)一個(gè)網(wǎng)站多次,但是還是算作一個(gè)人!)
傳統(tǒng)的方式,set保存用戶的id,然后就可以統(tǒng)計(jì)set中的元素?cái)?shù)量作為標(biāo)準(zhǔn)判斷
0.81%錯(cuò)誤率!統(tǒng)計(jì)UV任務(wù),可以忽略不計(jì)!
測(cè)試使用
127.0.0.1:6379> PFadd mykey a b c d e f g h i j # 創(chuàng)建第一組元素 mykey
(integer) 1
127.0.0.1:6379> pfcount mykey # 統(tǒng)計(jì)mykey元素的基數(shù)數(shù)量
(integer) 10
127.0.0.1:6379> PFadd mykey2 i j z x c v b n m # 創(chuàng)建第二組元素 mykey2
(integer) 1
127.0.0.1:6379> pfcount mykey2 # 統(tǒng)計(jì)mykey2元素的基數(shù)數(shù)量
(integer) 9
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 # 合并兩組 mykey mykey2 => mykey3 并集
OK
127.0.0.1:6379> pfcount mykey3 # 查看并集數(shù)量
(integer) 15
如果允許容錯(cuò),那么一定可以使用Hyperloglog!
如果不允許容錯(cuò),就使用set或者自己的數(shù)據(jù)類型即可
Bitmaps
位存儲(chǔ)
兩個(gè)狀態(tài)的都可以使用bitmaps,例如統(tǒng)計(jì)用戶信息:活躍、不活躍,登錄、未登錄,打卡等
Bitmaps位圖,數(shù)據(jù)結(jié)構(gòu)!都是操作二進(jìn)制位來(lái)進(jìn)行記錄,就只有0和1兩個(gè)狀態(tài)!
測(cè)試
使用bitmaps來(lái)記錄周一到周日的打卡!
周一:1 周二:0 周三 0…
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 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
查看某一天是否打卡
127.0.0.1:6379> getbit sign 3 # 查看第三天是否打卡
(integer) 1
127.0.0.1:6379> getbit sign 6
(integer) 1
127.0.0.1:6379> bitcount sign # 統(tǒng)計(jì)這周的打卡記錄
(integer) 4
6、事務(wù)
Redis 事務(wù)本質(zhì):一組命令的集合!(一起執(zhí)行)所有的命令都會(huì)被序列化,在事務(wù)執(zhí)行過(guò)程中,會(huì)按照順序執(zhí)行!
一次性、順序性、排他性!執(zhí)行一系列的命令
Redis事務(wù)沒有隔離級(jí)別的概念,只有發(fā)起執(zhí)行命令的時(shí)候才會(huì)執(zhí)行
Redis單條命令式保存原子性的,但是事務(wù)不保證原子性!
Redis的事務(wù):
- 開啟事務(wù)(multi)
- 命令入隊(duì)
- 執(zhí)行事務(wù)
正常執(zhí)行事務(wù)!
127.0.0.1:6379> multi # 開啟事務(wù)
OK
# 命令入隊(duì)
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec # 執(zhí)行事務(wù)
1) OK
2) OK
3) "v2"
4) OK
取消事務(wù)
127.0.0.1:6379> multi # 開啟事務(wù)
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> discard # 取消事務(wù)
OK
127.0.0.1:6379> get key4 #事務(wù)隊(duì)列中命令都不會(huì)被執(zhí)行
(nil)
編譯型異常
代碼有錯(cuò)誤!命令有錯(cuò)!事務(wù)中所有的命令都不會(huì)被執(zhí)行。
127.0.0.1:6379> multi # 開啟事務(wù)
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> getset k3 #錯(cuò)誤的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> exec # 執(zhí)行事務(wù)報(bào)錯(cuò)
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k4 # 所有的命令都不會(huì)被執(zhí)行
(nil)
運(yùn)行時(shí)異常
如果事務(wù)隊(duì)列中存在語(yǔ)法性,那么執(zhí)行命令的時(shí)候,其他命令式可以正常執(zhí)行,錯(cuò)誤命令拋出異常
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incr k1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range # 雖然第一條命令報(bào)錯(cuò)了,但是依舊執(zhí)行成功了
2) OK
3) OK
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"
監(jiān)控! Watch
樂觀鎖:
- 獲取version
- 更新時(shí)比較version
Redis測(cè)監(jiān)視測(cè)試
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 # 監(jiān)視 money 對(duì)象
OK
127.0.0.1:6379> clear
127.0.0.1:6379> multi # 事務(wù)正常結(jié)束,數(shù)據(jù)期間沒有發(fā)生變動(dòng),這個(gè)時(shí)候就正常執(zhí)行
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20
測(cè)試多線程修改值,使用watch可以當(dāng)做redis的樂觀鎖操作
127.0.0.1:6379> watch money # 監(jiān)視 money
OK
127.0.0.1:6379> multi # 開啟事務(wù)
OK
127.0.0.1:6379(TX)> decrby money 10
QUEUED
127.0.0.1:6379(TX)> incrby out 10
QUEUED
127.0.0.1:6379(TX)> exec # 在提交事務(wù)前,另一線程修改了我們的值,這個(gè)時(shí)候就會(huì)導(dǎo)致執(zhí)行失敗
(nil)
127.0.0.1:6379> unwatch # 如果發(fā)現(xiàn)事務(wù)執(zhí)行失敗,就先解鎖
OK
127.0.0.1:6379> watch money # 獲取最新的值,再次監(jiān)視,select version
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 30
QUEUED
127.0.0.1:6379(TX)> incrby out 30
QUEUED
127.0.0.1:6379(TX)> exec # 比對(duì)監(jiān)視的值是否發(fā)生了變化,如果沒有發(fā)生變化,那么可以執(zhí)行成功,如果變了就執(zhí)行失敗!
1) (integer) 970
2) (integer) 50
7、Jedis
使用java來(lái)操作Redis
Jedis是Redis官方推薦的java連接開發(fā)工具!使用java操作Redis中間件!如果你要使用java操作redis,那么一定要對(duì)Jedis十分的熟悉!
測(cè)試
1、導(dǎo)入對(duì)應(yīng)的依賴
<!--導(dǎo)入Jedis的包-->
<dependencies><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.2.0</version></dependency><!--導(dǎo)入fastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version></dependency>
</dependencies>
2、編碼測(cè)試:
- 連接數(shù)據(jù)庫(kù)
- 操作命令
- 斷開連接
import redis.clients.jedis.Jedis;public class TestPing {public static void main(String[] args) {// 1、new Jedis 對(duì)象即可Jedis jedis = new Jedis(URL,6379); // URL就是遠(yuǎn)程服務(wù)器的ip//Jedis所有的命令就是之前學(xué)習(xí)的所有指令String ping = jedis.ping();System.out.println(ping);}
}
結(jié)果為:PONG
8、SpringBoot整合
在SpringBoot2.x之后,原來(lái)使用的Jedis被替換為了lettuce
jedis:采用的直連,多個(gè)線程操作的話,是不安全的,如果想要避免不安全的,使用Jedis pool連接池。
1、導(dǎo)入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置連接
spring.redis.host=47.98.60.130
spring.redis.port=6379
3、測(cè)試
@SpringBootTest
class DemoApplicationTests {@Autowiredprivate RedisTemplate redisTemplate;@Testvoid contextLoads() {redisTemplate.opsForValue().set("name","khazix");redisTemplate.opsForValue().set("hello","編程");System.out.println(redisTemplate.opsForValue().get("name"));System.out.println(redisTemplate.opsForValue().get("hello"));}
}
在SpringBoot中的測(cè)試代碼也和Redis中的代碼差不多。
在遠(yuǎn)程服務(wù)器中獲取值:
127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\x04name"
2) "\xac\xed\x00\x05t\x00\x05hello"
我們可以編寫自己的RedisTemplate
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.net.UnknownHostException;@Configuration
public class RedisConfig {// 編寫我們自己的redisTemplate@Bean@SuppressWarnings("all")public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory)throws UnknownHostException {// 我們?yōu)榱碎_發(fā)方便,一般直接使用<String,Object>RedisTemplate<String,Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// 序列化配置Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);// String的序列化StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);// value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}
}
總結(jié)
以上是生活随笔為你收集整理的Redis概述和基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 第四天:Vue组件的slot以及webp
- 下一篇: Jedis无法远程连接阿里云服务器的re