1. Redis簡介
Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言撰寫、支持網路、可基于記憶體亦可持久化的日志型、Key-Value 資料庫,并提供多種語言的API,Redis 是一個高性能的key-value資料庫, redis的出現,在部分場合可以對關系資料庫起到很好的補充作用,它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便,
Redis支持主從同步,資料可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器,這使得Redis可執行單層樹復制,存盤可以有意無意的對資料進行寫操作,由于完全實作了發布/訂閱機制,使得從資料庫在任何地方同步樹時,可訂閱一個頻道并接收主服務器完整的訊息發布記錄,同步對讀取操作的可擴展性和資料冗余很有幫助,
redis的key都是字串String型別,它的value是多樣化的,如下圖:
| redis資料型別 | ENCODING回傳的編碼 | 底層對應的資料結構 |
|---|---|---|
| string | int | long型別的整數 |
| string | embstr | embstr編碼的簡單動態字串 |
| string | raw | 簡單動態字串 |
| list | ziplist | 壓縮串列 |
| list | linkedlist | 雙向鏈表 |
| hash | ziplist | 壓縮串列 |
| hash | ht | 字典 |
| set | intset | 整數集合 |
| set | ht | 字典 |
| zset | ziplist | 壓縮串列 |
| zset | skiplist | 跳表 |
2. Redis的五種資料型別
2.1 字串物件(String)
字串物件的模型:

redis底層提供了三種不同的資料結構實作字串物件,根據不同的資料自動選擇合適的資料結構,這里的字串物件并不是指的純粹的字串,數字也是可以的,
-
int:當資料是long型別的整數字串時,底層使用long型別的整數實作,這個值會直接存盤在字串物件的ptr屬性中,同時OBJECT ENCODING為int,
-
raw:當資料為長度大于44位元組的字串時,底層使用簡單動態字串實作,說到這里就不得不提下redis的簡單隨機字串(Simple Dynamic String,SDS),SDS有三個屬性,free,len和buf,free存的是還剩多少空間,len存的是目前字串長度,不包含結尾的空字符,buf是一個list,存放真實字串資料,包含free和空字符,針對SDS本文不做詳細介紹,歡迎點擊SDS了解,
-
embstr:當資料為長度小于44位元組的字串時,底層使用embstr編碼的簡單動態字串實作,相比于raw,embstr記憶體分配只需要一次就可完成,分配的是一塊連續的記憶體空間,
2.2 串列物件(List)
串列物件的模型:

redis中的串列物件經常被用作訊息佇列使用,底層采用ziplist和linkedlist實作,大家使用的時候當作鏈表使用就可以了,
-
ziplist
串列物件使用ziplist編碼需要滿足兩個要求,一是所有字串長度都小于設定值值64位元組(可以在組態檔中修改list-max-ziplist-value欄位改變),二是所存元素數量小于設定值512個(可以在組態檔中修改list-max-ziplist-entries欄位改變),ziplist類似與python中的list,占用一段連續的記憶體地址,由此減小指標記憶體占用,

zlbytes:占記憶體總數
zltail:到尾部的偏移量
zllen:內部節點數
node:節點
zlend:尾部標識
previous_entry_length:前一節點的長度
encoding:資料型別
content:真實資料
遍歷的時候會根據zlbytes和zltail直接找到尾部節點nodeN,然后根據每個節點的previous_entry_length反向遍歷,增加和洗掉節點會導致其他節點連鎖更新,因為每個節點都存盤了前一節點的長度,
-
linkedlist
linkedlist有三個屬性,head,tail和len,head指向鏈表的頭部,tail指向鏈表的尾部,len為鏈表的長度,

2.3 哈希型別物件(Hash)
哈希型別物件的模型:

redis的value型別hash型別,其實就是map型別,就是在值的位置放一個map型別的資料,大家想詳細了解一下,可以參考一下這篇文章:https://www.jianshu.com/p/658365f0abfc ,
2.4 集合物件(Set)
集合物件型別的模型:
Set型別的value保證每個值都不重復,

redis中的集合物件底層有兩種實作方式,分別有整數集合和hashtable,當所有元素都是整數且元素數小于512(可在組態檔中set-max-intset-entries欄位配置)時采用整數集合實作,其余情況都采用hashtable實作,hashtable請移駕上文鏈接查閱,接下來介紹整數集合intset,intset有三個屬性,encoding:記錄數字的型別,有int16,int32和int64等,length:記錄集合的長度,content:存盤具體資料,具體結構如下圖:

2.5 有序集合物件
有序集合物件(zset)和集合物件(set)沒有很大區別,僅僅是多了一個分數(score)用來排序,
redis中的有序集合底層采用ziplist和skiplist跳表實作,當所有字串長度都小于設定值值64位元組(可以在組態檔中修改list-max-ziplist-value欄位改變),并且所存元素數量小于設定值512個(可以在組態檔中修改list-max-ziplist-entries欄位改變)使用ziplist實作,其他情況均使用skiplist實作,跳躍表的實作原理這里偷個懶,給大家推薦一篇寫的非常好的博客,點擊查看跳躍表原理,
3. Redis的安裝
可以去官網或者中文網下載Redis,redis的windows版本現在已經不更新了,所以我們安裝redis的6.0.3版本,這個版本支持的東西很多,在此次教程中,我們只對redis的五種資料型別做解釋和學習,
官網:https://redis.io/
中文網:https://www.redis.net.cn/
本教程安裝的redis版本為6.0.3版本,redis使用C語言撰寫的,CentOS7的gcc自帶版本為4.8.5,而redis6.0+需要的gcc版本為5.3及以上,所以需要升級gcc版本,
下載Linux版本的tar.gz包,解壓以后進入解壓產生的包:
cd redis-6.0.3
發現沒有bin目錄,這里需要通過make進行安裝,
# 先檢查gcc的環境
gcc -v
# 查看gcc版本
yum -y install centos-release-scl
# 升級到9.1版本
yum -y install devtoolset-9-gcc devtoolset-9-gcc- c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
#以上為臨時啟用,如果要長期使用gcc 9.1的話:
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
# 進入redis解壓檔案
make
# 6.0的坑,gcc版本 9.0 以上
# 等待完畢
執行完make操作之后,就可以在redis目錄看到src目錄了,進入src目錄后就可以看到redis-server和redis-cli,
這里建議將Redis的組態檔復制,保留一份原生的組態檔,
redis的配置大家可以在網上搜一下常用的配置,在這里給大家推薦一個常用的配置,比較詳細:
https://blog.csdn.net/ymrfzr/article/details/51362125
到這里redis就可以啟動并且正常訪問了,
注意:一定要將redis的IP地址系結注釋掉,允許所有的IP地址訪問,不然我們從Windows訪問就訪問不了,
注釋掉下面的這一行:

同時關閉Redis的服務保護模式,將protected-mode設定為no,如下:

4. Spring Boot 整合 Redis
-
4.1 搭建工程,引入依賴
搭建工程的操作我這里就不在寫出來了,直接上
pom.xml:<!--springboot父工程--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <!--springboot-web組件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.2.2.RELEASE</version> </dependency> <!--redis整合springboot組件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.3.0.RELEASE</version> </dependency> <!--lombok組件--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> </dependency> </dependencies> -
4.2 redis的配置
專案的組態檔,
application.yml:butterflytri: host: 127.0.0.1 server: port: 8080 # 應用埠 servlet: context-path: /butterflytri # 應用映射 spring: application: name: redis # 應用名稱 redis: host: ${butterflytri.host} # redis地址 port: 6379 # redis埠,默認是6379 timeout: 10000 # 連接超時時間(ms) database: 0 # redis默認情況下有16個分片,這里配置具體使用的分片,默認是0 jedis: # 使用連接redis的工具-jedis pool: max-active: 8 # 連接池最大連接數(使用負值表示沒有限制) 默認 8 max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制) 默認 -1 max-idle: 8 # 連接池中的最大空閑連接 默認 8 min-idle: 0 # 連接池中的最小空閑連接 默認 0另外還有額外的配置類
RedisConfig.java:package com.butterflytri.config; 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.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author: WJF * @date: 2020/5/24 * @description: RedisConfig */ @Configuration public class RedisConfig { /** * redis鍵值對的值的序列化方式:通用方式 * @return RedisSerializer */ private RedisSerializer redisValueSerializer() { return new GenericJackson2JsonRedisSerializer(); } /** * redis鍵值對的健的序列化方式:所有的健都是字串 * @return RedisSerializer */ private RedisSerializer redisKeySerializer() { return new StringRedisSerializer(); } @Bean("redisTemplate") public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(redisKeySerializer()); redisTemplate.setValueSerializer(redisValueSerializer()); return redisTemplate; } } -
4.3 redisTemplate的使用
對
value型別的值的CRUD:ValueServiceImpl.java:package com.butterflytri.service.impl; import com.butterflytri.service.ValueService; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * @author: WJF * @date: 2020/5/27 * @description: ValueServiceImpl */ @Service public class ValueServiceImpl implements ValueService { @Resource private RedisTemplate<String, Object> redisTemplate; @Override public void addValue(String key, Object value) { redisTemplate.opsForValue().set(key,value); } @Override public Object get(String key) { return redisTemplate.opsForValue().get(key); } @Override public Object update(String key, Object newValue) { return redisTemplate.opsForValue().getAndSet(key,newValue); } @Override public void delete(String key) { redisTemplate.delete(key); } }對
List型別的值的CRUD:這里我加了列舉型別用來控制增加的位置,因為List型別對應的是鏈表,
ListServiceImpl.java:package com.butterflytri.service.impl; import com.butterflytri.enums.OpsType; import com.butterflytri.service.ListService; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; /** * @author: WJF * @date: 2020/5/28 * @description: ListServiceImpl */ @Service public class ListServiceImpl implements ListService { @Resource private RedisTemplate<String, Object> redisTemplate; @Override public void addList(String key, List<Object> list, OpsType type) { switch (type) { case RIGHT: redisTemplate.opsForList().rightPushAll(key, list); break; case LEFT: redisTemplate.opsForList().leftPushAll(key, list); break; default: throw new RuntimeException("type不能為null"); } } @Override public void add(String redisKey, Object value, OpsType type) { switch (type) { case RIGHT: redisTemplate.opsForList().rightPush(redisKey, value); break; case LEFT: redisTemplate.opsForList().leftPush(redisKey, value); break; default: throw new RuntimeException("type不能為null"); } } @Override public List<Object> get(String key) { return redisTemplate.opsForList().range(key, 0, -1); } @Override public Object update(String key, Object value, Integer index) { Object obj = redisTemplate.opsForList().index(key, index); redisTemplate.opsForList().set(key,index,value); return obj; } @Override public void delete(String key) { redisTemplate.delete(key); } @Override public void deleteValue(String redisKey, OpsType type) { switch (type) { case RIGHT: redisTemplate.opsForList().rightPop(redisKey); break; case LEFT: redisTemplate.opsForList().leftPop(redisKey); break; default: throw new RuntimeException("type不能為null"); } } }對
Hash型別的值的CRUD:hash型別是我們使用最常用的型別,
HashServiceImpl.java:package com.butterflytri.service.impl; import com.butterflytri.service.HashService; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Map; /** * @author: WJF * @date: 2020/5/28 * @description: HashServiceImpl */ @Service public class HashServiceImpl implements HashService { @Resource private RedisTemplate<String, Object> redisTemplate; @Override public void addHashAll(String key, Map<String, Object> value) { redisTemplate.opsForHash().putAll(key, value); } @Override public void addHash(String redisKey, String key, Object value) { redisTemplate.opsForHash().put(redisKey, key, value); } @Override public Object get(String redisKey, String key) { return redisTemplate.opsForHash().get(redisKey, key); } @Override public Object update(String redisKey, String key, Object value) { Object obj = this.get(redisKey, key); this.delete(redisKey,key); redisTemplate.opsForHash().put(redisKey, key, value); return obj; } @Override public void delete(String redisKey, String key) { redisTemplate.opsForHash().delete(redisKey, key); } @Override public void deleteAll(String redisKey) { redisTemplate.delete(redisKey); } }對
Set的值的CRUD:package com.butterflytri.service.impl; import com.butterflytri.service.SetService; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Set; /** * @author: WJF * @date: 2020/5/28 * @description: SetServiceImpl */ @Service public class SetServiceImpl implements SetService { @Resource private RedisTemplate<String, Object> redisTemplate; @Override public void addAll(String key, Set<Object> set) { redisTemplate.opsForSet().add(key,set); } @Override public void add(String key, Object value) { redisTemplate.opsForSet().add(key,value); } @Override public Set<Object> findAll(String key) { return redisTemplate.opsForSet().members(key); } @Override public void deleteValue(String key, Object value) { redisTemplate.opsForSet().remove(key,value); } @Override public void delete(String key) { redisTemplate.delete(key); } }對
ZSet型別的值的CRUD:package com.butterflytri.service.impl; import com.butterflytri.service.SortedSetService; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.LinkedHashSet; /** * @author: WJF * @date: 2020/5/28 * @description: SortedSetServiceImpl */ @Service public class SortedSetServiceImpl implements SortedSetService { @Resource private RedisTemplate<String, Object> redisTemplate; @Override public void add(String key, String value, Double score) { redisTemplate.opsForZSet().add(key, value, score); } @Override public LinkedHashSet<Object> findAll(String key) { return (LinkedHashSet<Object>) redisTemplate.opsForZSet().range(key,0,-1); } @Override public Long count(String key, Double scoreFrom, Double scoreTo) { return redisTemplate.opsForZSet().count(key,scoreFrom,scoreTo); } @Override public LinkedHashSet<Object> findByScore(String key, Double scoreFrom, Double scoreTo) { return (LinkedHashSet<Object>) redisTemplate.opsForZSet().rangeByScore(key,scoreFrom,scoreTo); } @Override public Long rank(String key, Object value) { return redisTemplate.opsForZSet().rank(key,value); } @Override public void remove(String key, String value) { redisTemplate.opsForZSet().remove(key,value); } @Override public void delete(String key) { redisTemplate.delete(key); } }redis的Java客戶端有很多,在這里我們使用的是jedis,還有一個很好的Java語言的客戶端叫lettuce,大家可以去了解一下,Spring從不重復造輪子,只會簡化輪子的使用,redisTemplate就是一個超級簡單的使用實作,到這里redis整合Spring Boot 就結束了,
5. 專案地址
本專案傳送門:
- GitHub ---> spring-data-redis
- Gitee ---> spring-data-redis
此教程會一直更新下去,覺得博主寫的可以的話,關注一下,也可以更方便下次來學習,
- 作者:Butterfly-Tri
- 出處:Butterfly-Tri個人博客
- 著作權所有,歡迎保留原文鏈接進行轉載??
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/160752.html
標籤:Java
上一篇:博客園添加live2d看板娘
