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等客戶端,使用很方便。java
Redis支持主從同步。數據能夠從主服務器向任意數量的從服務器上同步,從服務器能夠是關聯其餘從服務器的主服務器。這使得Redis可執行單層樹複製。存盤能夠有意無心的對數據進行寫操做。因爲徹底實現了發佈/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發佈記錄。同步對讀取操做的可擴展性和數據冗餘頗有幫助。node
redis的key都是字符串String
類型,它的value是多樣化的,以下圖:python
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.1 字符串對象(String)c++
字符串對象的模型:git
redis底層提供了三種不一樣的數據結構實現字符串對象,根據不一樣的數據自動選擇合適的數據結構。這裏的字符串對象並非指的純粹的字符串,數字也是能夠的。github
int:當數據是long類型的整數字符串時,底層使用long類型的整數實現。這個值會直接存儲在字符串對象的ptr屬性中,同時OBJECT ENCODING爲int。web
raw:當數據爲長度大於44字節的字符串時,底層使用簡單動態字符串實現,說到這裏就不得不提下redis的簡單隨機字符串(Simple Dynamic String,SDS),SDS有三個屬性,free,len和buf。free存的是還剩多少空間,len存的是目前字符串長度,不包含結尾的空字符。buf是一個list,存放真實字符串數據,包含free和空字符。針對SDS本文不作詳細介紹,歡迎點擊SDS瞭解。redis
embstr:當數據爲長度小於44字節的字符串時,底層使用embstr編碼的簡單動態字符串實現。相比於raw,embstr內存分配只須要一次就可完成,分配的是一塊連續的內存空間。spring
2.2 列表對象(List)shell
列表對象的模型:
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實現,跳躍表的實現原理這裏偷個懶,給你們推薦一篇寫的很是好的博客,點擊查看跳躍表原理。
能夠去官網或者中文網下載Redis。redis的windows版本如今已經不更新了,因此咱們安裝redis的6.0.3版本,這個版本支持的東西不少,在這次教程中,咱們只對redis的五種數據類型作解釋和學習。
本教程安裝的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.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 就結束了。
本項目傳送門:
此教程會一直更新下去,以爲博主寫的能夠的話,關注一下,也能夠更方便下次來學習。