史上最全redis教程

個人最近總結了一下redis的知識如下,可能有的東西寫的比較雜,只是爲了自我總結一下。

  1. redis簡介
  • 什麼是redis
    Redis的的是完全開源免費的,遵守BSD協議,是一個高性能的鍵值數據庫。是當前最熱門的的的NoSql數據庫之一,也被人們稱爲數據結構服務器。Redis以內存作爲數據存儲介質,所以讀寫數據的效率極高,遠遠超過數據庫。以設置和獲取一個256字節字符串爲例,它的讀取速度可高達110000次/s,寫速度高達81000次/s。
    Redis跟memcache不同的是,儲存在Redis中的數據是持久化的,斷電或重啓後,數據也不會丟失。因爲Redis的存儲分爲內存存儲、磁盤存儲和log文件三部分,重啓後,Redis可以從磁盤重新將數據加載到內存中,這些可以通過配置文件對其進行配置,正因爲這樣,Redis才能實現持久化。
    Redis支持主從模式,可以配置集羣,這樣更利於支撐起大型的項目,這也是Redis的一大亮點。

  • redis到底有多快
    Redis採用的是基於內存的採用的是單進程單線程模型的 KV 數據庫,由C語言編寫,官方提供的數據是可以達到100000+的QPS(每秒內查詢次數)。這個數據不比採用單進程多線程的同樣基於內存的 KV 數據庫 Memcached 差。

  • redis爲什麼這麼快
    1、完全基於內存,絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間複雜度都是O(1);
    2、數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門進行設計的;
    3、採用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因爲可能出現死鎖而導致的性能消耗;
    4、使用多路I/O複用模型,非阻塞IO;
    5、使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;
    以上幾點都比較好理解,下邊我們針對多路 I/O 複用模型進行簡單的探討:
    (1)多路 I/O 複用模型
    多路I/O複用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閒的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,於是程序就會輪詢一遍所有的流(epoll 是隻輪詢那些真正發出了事件的流),並且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。
    這裏“多路”指的是多個網絡連接,“複用”指的是複用同一個線程。採用多路 I/O 複用技術可以讓單個線程高效的處理多個連接請求(儘量減少網絡 IO 的時間消耗),且 Redis 在內存中操作數據的速度非常快,也就是說內存內的操作不會成爲影響Redis性能的瓶頸,主要由以上幾點造就了 Redis 具有很高的吞吐量。

  • redis爲什麼是單線程的
    官方FAQ表示,因爲Redis是基於內存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存的大小或者網絡帶寬。既然單線程容易實現,而且CPU不會成爲瓶頸,那就順理成章地採用單線程的方案了(畢竟採用多線程會有很多麻煩!),並且正是由於在單線程模式的情況下已經很快了,就沒有必要在使用多線程了!

  1. 安裝

1、下載對應版本的壓縮包,上傳到對應的linux服務器上,解壓縮
下載地址https://redis.io/
2、解壓tar -zxvf redis-5.0.5.tar.gz
3、redis是由C語言編寫的,它的運行需要C環境,所以編譯前需安裝 gcc
yum install gcc-c++
4、編譯:進入解壓後的 redis-5.0.5 目錄,執行 make 命令(稍慢)
5、安裝:進入 src 目錄後執行 make install(很快)
6、修改redis 的核心配置文件 redis.conf
(1) 註釋掉 bind 127.0.0.1 這一行(解決只能特定網段連接的限制)
(2) 將 protected-mode 屬性改爲 no (關閉保護模式,不然會阻止遠程訪問)
(3) 將 daemonize 屬性改爲 yes (這樣啓動時就在後臺啓動)
(4) 設置密碼(可選,個人建議還是設個密碼)
修改完成後,wq保存並退出(先按Esc,接着輸入 :wq)
7、進入到src目錄下直接輸入redis-server …/etc/redis.conf啓動redis
使用redis-cli可以進入redis客戶端,設置的密碼的話,需要輸入相應的密碼。
8、也可以下載可視化工具連接RedisDesktopManager連接redis
下載地址https://github.com/qishibo/AnotherRedisDesktopManager/releases

  1. redis基本知識點
    redis數據結構:
    Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
    1、String類型是二進制安全的,意思是redis的String可以包含任何數據。比如jpg圖片或者序列化的對象。string 類型的值最大能存儲 512MB
    2、Redis hash 是一個鍵值(key=>value)對集合,Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用於存儲對象,每個 hash 可以存儲 232 -1 鍵值對(40多億)
    3、List Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)列表最多可存儲 232 - 1 元素 (4294967295, 每個列表可存儲40多億)。lpush runoob mongodb 、、
    4、Redis 的 Set 是 string 類型的無序集合,集合是通過哈希表實現的,所以添加,刪除,查找的複雜度都是 O(1),根據集合內元素的唯一性,第二次插入的元素將被忽略,集合中最大的成員數爲 232 - 1(4294967295, 每個集合可存儲40多億個成員)。
    sadd key member
    smembers runoob
    5、zset(sorted set:有序集合),不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來爲集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。zadd zset 0 test
    阿斯蒂芬打算在這裏插入圖片描述
    1、redisTemplate.opsForValue().setIfAbsent(key, value)
    如果鍵不存在則新增,存在則不改變已經有的值。
    2、redisTemplate.opsForValue().getAndSet(key, value)
    獲取輸出舊值,修改舊值
    1、2可以一起使用實現redis的分佈式鎖
  2. 結合SpringBoot使用redis
    4.1. 添加pom依賴
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>

4.2 在application.properties中加入redis配置

#-------------redis配置------------
# Redis數據庫索引(默認爲0)
#spring.redis.database=0
# Redis服務器地址
spring.redis.host=xxxxxxxxx
# Redis服務器連接端口
spring.redis.port=6379
# Redis服務器連接密碼(默認爲空)
spring.redis.password=redis
# 連接池最大連接數(使用負值表示沒有限制)
spring.redis.jedis.pool.max-active=8
# 連接池最大阻塞等待時間(使用負值表示沒有限制,s)
spring.redis.jedis.pool.max-wait=-1
# 連接池中的最大空閒連接
spring.redis.jedis.pool.max-idle=8
# 連接池中的最小空閒連接
spring.redis.jedis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=1000

4.3. 初始化配置類

package com.zyu.springandmybatis.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;


@Configuration
public class RedisConfig {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
    {
        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);

        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
    {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}


4.4 創建一個service測試使用redisTemplate往redis服務器中存數據取數據

package com.zyu.springandmybatis.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class RedisService {
    @Autowired
    RedisTemplate redisTemplate;
    //    測試redis
    //存String類型數據
    public void setToRedis(){
        redisTemplate.opsForValue().set("testString","testString");
        String test= (String) redisTemplate.opsForValue().get("testString");
        System.out.println(test);
    }
    //存Hash類型數據
    public void setHash(){
        Map<String,String> map=new HashMap<>();
        map.put("key1","value1");
        map.put("key2","value2");
        map.put("key3","value3");
        map.put("key4","value4");
        map.put("key5","value5");
        redisTemplate.opsForHash().putAll("map1",map);
        Map<String,String> resultMap= redisTemplate.opsForHash().entries("map1");
        List<String> reslutMapList=redisTemplate.opsForHash().values("map1");
        Set<String>resultMapSet=redisTemplate.opsForHash().keys("map1");
        String value=(String)redisTemplate.opsForHash().get("map1","key1");
        System.out.println("value:"+value);
        System.out.println("resultMapSet:"+resultMapSet);
        System.out.println("resultMap:"+resultMap);
        System.out.println("resulreslutMapListtMap:"+reslutMapList);
    }
    //存List類型數據
    public void setList(){
        List<String> list1=new ArrayList<String>();
        list1.add("a1");
        list1.add("a2");
        list1.add("a3");

        List<String> list2=new ArrayList<String>();
        list2.add("b1");
        list2.add("b2");
        list2.add("b3");
        redisTemplate.opsForList().leftPush("listkey1",list1);
        redisTemplate.opsForList().rightPush("listkey2",list2);
        redisTemplate.opsForList().leftPushAll("list",list1);
        List<String> resultList1=(List<String>)redisTemplate.opsForList().leftPop("listkey1");
        List<String> resultList2=(List<String>)redisTemplate.opsForList().rightPop("listkey2");
        System.out.println("resultList1:"+resultList1);
        System.out.println("resultList2:"+resultList2);

    }
    //存set類型數據
    public void setSet(){
        Set<String> set1=new HashSet<String>();
        set1.add("set1");
        set1.add("set2");
        set1.add("set3");
        redisTemplate.opsForSet().add("set1",set1);
        Set<String> resultSet =redisTemplate.opsForSet().members("set1");
        System.out.println("resultSet:"+resultSet);
    }
}

4.5 創建一個controller訪問服務

package com.zyu.springandmybatis.controller;

import com.zyu.springandmybatis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "redis")
public class RedisController {
    @Autowired
    RedisService redisService;

    @RequestMapping(value = "/setString")
    public void setToRedis(){
        redisService.setToRedis();
    }

    @RequestMapping(value = "/set")
    public void set(){
        redisService.setSet();
    }

    @RequestMapping(value = "/hash")
    public void hash(){
        redisService.setHash();
    }
    @RequestMapping(value = "/list")
    public void list(){
        redisService.setList();
    }

}

4.6 也可以使用註解
要先在啓動類中加入@EnableCaching // 開啓緩存註解
1、@Cacheable(cacheNames= “”)能夠達到緩存方法的返回對象的效果。
value 或 cacheNames 屬性做鍵,key 屬性則可以看作爲 value 的子鍵, 一個 value 可以有多個 key 組成不同值存在 Redis 服務器。
2、@CachePut緩存新增的或更新的數據到緩存,其中緩存名稱爲people,數據的key是person的id。
3、@CacheEvict從緩存people中刪除key爲id的數據。
配合redis來做緩存

done

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章