Reids入門到SpringBoot整合入門

1.NoSql的特點

  1. 方便擴展,數據之間沒有關係型數據庫的三大範式
  2. 存取數據很塊,因爲redis是直接加載在內存,沒有和磁盤交互
  3. 數據類型也很多,而且不用事先設計

大數據時代:高併發,高可擴,高性能

2.Redis(遠程字典服務) 結構化數據庫

它能幹嘛

  1. 內存存儲,持久化,內存斷電即失,所以需要持久化(adb,rof)

  2. 效率高,緩存

  3. 地圖信息分析

  4. 消息隊列

  5. 計時器,瀏覽量 …

Windows和linux下都可以安裝,官網可以下載,它的安裝一點也不難,新手不要怕

基本環境安裝

yum insatll gcc-c++    gcc -v查看一下安裝
安裝完環境   make   會編譯環境  make insatll查看一下

一定要記住redis安裝目錄

可以設置爲可以後臺運行,到時候可以ps -ef|grep redis可以看得到執行目錄

進入redis.conf配置

修改完:wq!保存,退出重啓redis

redis-server xxxx/redis.conf

redis-cli -p 6379 端口啓動

基本命令
set key
get key 
keys *
ping 連接成功會反應pong
查看redis狀態
 ps -ef|grep redis
 losf -i:6379
關閉redis
 127.0.0.1:6379> shutdown
 再exit
性能測試工具

redis-benchmark -h localhost -p 6379 -c 100 -n 100000 (100個併發連接,每個10萬個請求)

知識小驛站

  1. redis默認16數據庫,而我們一開始用的是第0個,我們可以用select num進行切換 dbsize數據庫大小

  2. keys * 查看所有key flushAll 清空全部數據庫 flushdb 清空當前數據庫

  3. redis是單線程的,它基於內存,跟cpu沒多大關係,主要是機器的內存,和網絡速率問題,單線程也沒有多線程麻煩,就使用單線程了

  4. C語言大佬寫的

開心一刻

爲什麼redis端口默認是6379

redis的作者看電視節目的MERZ明星,然後那明星經常說一些梗來逗大家開心,然後作者後來命名又覺得這個名字體現了技術,造梗很厲害有技術價值的意思,由於是數字端口,然後就想到了手機九宮格對應的6379

redis單線程爲什麼還這麼快

首先多線程的話一定會有上下文的切換,從用戶態到內核態的調用執行,而這過程耗時,而且redis不僅存放在內存,可以直接基於內存的存儲,使用單線程又不用切換,多次讀寫也只是在一個cpu上,同一塊內存,無須耗費其它時間

講個故事

打個比方,現在有個工人(CPU)要雕刻玉佛。
  工廠有個大倉庫,裏面放道很多玉石的材料。工人從倉庫裏取出來玉,進行加工。但倉庫太大了,遠離他的雕刻的機器和設備,至少100裏地。每雕刻一塊玉就來回跑太累,特別費專時間。
  於是老闆給他放了一張大桌子,先放一批玉過來,都雕刻完了再送回倉屬庫。
  這個桌子就是內存

那麼從桌子到磁盤的距離肯定小於機器到桌子再到磁盤的距離,也小於機器直接到倉庫的距離,

所以cpu的磁盤io時間花的比內存久,多線程都是cpu在調度,

3.五大數據類型

先來點基本的命令

set name lichu
set age 11                   EXIST age //返回1,說明存在
get "age" 
move name 1 //移動到數據庫1
EXPIRE name 10  //10秒後過期      ttl  name//查看過期時間
type key //查看key類型

1.String類型

append key value //追加字符串,如果key不存在,那就set key
strlen  key//字符串長度
set num 1
incr num//加一     decr num//減一  都是類型變爲Integer
incrby key 10//增量10
decrby key 10//減小10
    
 getrange key 0 3//從字符串的0到3得位置  0 -1 全部
 setrange  key  1 xx  //在key字符串的1位置開始替換 xx  比如abc 替換爲axx
 ====================================================
 setex   key 30  "hello"                        //設置過期時間
    
 setnx   mykey  "redis"                 //不存在才能設置成功返回1,存在返回失敗0
    
 meset key1 value1 key2 value2         //批量設置key,非原子性操作,能成功的就成功,不成功的不設值
 mesetnx key1 value1 key2 value2         //批量設置key,原子性操作一個不成功,全都不成功
 meget key1 key2                       //可以取得多個key的值
    
 SET user:1 {name:zhangsan,age:3}      //可以設置一個json字符串

getset db redis  //先get出key的值,再設置,第一次get爲空   這個就有點像cas了,比較並交換
    

2.List類型

類似一個雙端隊列,左右都可以存取值

所有list命令基本都是l開頭

LPUSH list two
LPUSH list three  
LRange list 0 -1   //順序是three在前,因爲後來居上  獲取全部list裏的元素
LRange list 0 1   //獲取0,1下標的兩個元素
RPUSH list four    //從右邊加值,所以,four在最底下    
LPOP list   //左
RPOP list  //右移除第一個值
//集合裏面可以存在重複值    
lindex  list 1  //通過下標獲取集合的值
llen list //相當於list.size()
lrem list 1 one  // 移除指定個數的一個值
 
 
ltrim list 1 2 //截取出下標1開始的2個元素,返回這個集合,其它沒截取的就丟棄了
RPOPLPUSH list newlist //移除列表最後一個元素,並且添加上給第一個
lset list 0 item //更新當前下標的值,前提得該集合這位置存在一個值
    
linsert list before  "world"  "hello"   //在world前面加一個值hello
linsert list after  "world"  "hello"    

3.Set類型

sadd set "hello"  //添加值
SMEMBERS set  //查看set內容,遍歷
SISMEMBER set hello //set.contains(key)
Srem set hello  //移除元素
scard set //size()方法
sandMember set     //隨機set一個元素出來
spop set   //隨機刪除一個key
    
smove set set2 "hello"  //將set中得值移動到set2中
 //共同關注,也感興趣,二度好友,推薦好友(共同好友很多就推薦了)
SDIFF set set2  //差集,去掉set中和set2相同得,剩下得set就是set和set2得差集
SINTER set set2  //交集
SUNION set set2  //並集

4.Hash類型

map集合!! Map<key,Map<field,value>>

hset hash field value   //設值
hget hash field   //取值
hmset hash field value  field2 value2  //同時設置多個值
hmget hash field field2   //獲取對應得值
hgetall hash  //獲取所有得鍵值對
hdel hash field  //刪除指定得鍵
hlen hash   //長度
HEXISTS hash  field//判斷key是否存在
hkeys hash //顯示所有key
    
hincrby hash field 1 //field加一,如果是-1,就是減1

5. ZSet類型

在set得基礎上追加了一個值 set k1 v1 | zset k1 age v1

zadd  zset  1 one  //增加
zadd zset 1 one 2 two //多個
zrange zset 0 -1
zrangebyscore 字段 -inf +inf //範圍
ZREVERRANGE 字段 -inf +inf value

4.Redis事務

redis事務不保證原子性,單條命令原子性,沒有隔離級別的概念

multi
命令入隊
set k1 vi
exec
完成事務

multi
命令入隊
set k1 vi
discard  //放棄事務,命令撤回

編譯型異常(代碼有問題,命令有錯),都不會執行,而且直接失敗

multi

set k1 v1

seta k2 v2

exec

這時候get k1會發現沒值

運行時異常,某個地方報錯,其它地方仍然會執行,錯誤的地方拋出異常

multi

set k1 v1

incr k2

exec

這時候get k1 仍然有值,但是incr 會報錯

1.監控

悲觀鎖與樂觀鎖(概念可以去看我的其它文章有介紹)

set money 100
set out 0
watch money  //監視
multi
Decrby money 20
incrby out 20
exec
這樣出來效果很正常一個80一個20

如果是多線程下

一個線程

watch money  //監視
multi
Decrby money 20
incrby out 20

另一個線程

set money 100
get money

這時第一個線程exec會提交事務失敗回滾,類似樂觀鎖,watch先獲取了值,比較發現值不是了所以會失敗

watch完,要記得unwatch,要再次watch獲取最新的版本值,CAS無鎖原理

5.Jedis

Redis官方推薦java連接開發工具,他是個中間件

記得打開服務,如果是遠程redis,那要修改配置redis.conf

設置保護域關掉,然後bind本地也關閉,記得再弄一個密碼,現在遠程連接需要一個密碼

本地的話,不需要這些,因爲redis默認綁定本地

//測試一下
Jedis redis=new Jedis("127.0.0.1",6379);
//如果是遠程可以點進他源碼自行參考測試方式
僞代碼:sout(jedis.ping());

五大類型等對應API都在java中有對應的方法

其它的類型也是一樣的,都有對應的方法,這裏就不一一列舉,因爲隨便可以查的到

6.SpringBoot整合

引入依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>

在springboot 2.x之後底層redis已經不用jedis了,因爲直連,多個線程是不安全的,使用jedis pool 連接池如BIO

改用了lettuce:採用netty,實例可以在多個線程之間共享,不存在線程不安全的情況,可以減少線程數據,更像NIO模式

裏面有個RedisAutoConfig,裏面有個方法是redistemplate,一旦我們配置,自動配置就失效了

測試一下

//application.properties
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
//其實可以去網上收索需要配置額外的可以再加,也可以去看他的源碼裏面到底有啥屬性可以配

@Autowired
RedisTemplate redistemplate;
@Test
void contextLoads(){
   redistemplate.opsForValue().set("mykey","myValue");
   sout(redistemplate.opsForValue().get("mykey"));
}

但是如果你存入中文字符串,會發現keys * 裏面不是中文值

默認是jdk序列化,會讓中文轉義

所以這時候,我們一般都會用自己的RedisConfig類來統一管理redis配置

來重新加入config的測試

user類,注意序列化

package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

import java.io.Serializable;

@Component
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    /**
     * name : asd
     * age : 1
     */
    private String name;
    private int age;

}

//Test

    @Test
    void test() {
//        RedisConnection connection=redisTemplate.getConnectionFactory().getConnection();
//        connection.flushDb();
//        connection.flushAll();

        //真實開發一般用json
        User user = new User("章北海", 18);
        try {
            String json=new ObjectMapper().writeValueAsString(user);
            redisTemplate.opsForValue().set("user",json);
            System.out.println(redisTemplate.opsForValue().get("user"));

        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

    }

直接傳遞對象報錯,沒有序列化

配置具體的序列化方式

package com.example.config;

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 {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<String , Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);

        //Json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om=new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer=new StringRedisSerializer();

        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();


        return template;
    }
}

1.utils工具類


/**

 * Redis工具類,使用之前請確保RedisTemplate成功注入

 *

 * @author ye17186

 * @version 2019/2/22 10:48

 */

public class RedisUtils {

 

    private RedisUtils() {

    }

 

    @SuppressWarnings("unchecked")

    private static RedisTemplate<String, Object> redisTemplate = SpringUtils

        .getBean("redisTemplate", RedisTemplate.class);

 

    /**

     * 設置有效時間

     *

     * @param key Redis鍵

     * @param timeout 超時時間

     * @return true=設置成功;false=設置失敗

     */

    public static boolean expire(final String key, final long timeout) {

 

        return expire(key, timeout, TimeUnit.SECONDS);

    }

 

    /**

     * 設置有效時間

     *

     * @param key Redis鍵

     * @param timeout 超時時間

     * @param unit 時間單位

     * @return true=設置成功;false=設置失敗

     */

    public static boolean expire(final String key, final long timeout, final TimeUnit unit) {

 

        Boolean ret = redisTemplate.expire(key, timeout, unit);

        return ret != null && ret;

    }

 

    /**

     * 刪除單個key

     *

     * @param key 鍵

     * @return true=刪除成功;false=刪除失敗

     */

    public static boolean del(final String key) {

 

        Boolean ret = redisTemplate.delete(key);

        return ret != null && ret;

    }

 

    /**

     * 刪除多個key

     *

     * @param keys 鍵集合

     * @return 成功刪除的個數

     */

    public static long del(final Collection<String> keys) {

 

        Long ret = redisTemplate.delete(keys);

        return ret == null ? 0 : ret;

    }

 

    /**

     * 存入普通對象

     *

     * @param key Redis鍵

     * @param value 值

     */

    public static void set(final String key, final Object value) {

 

        redisTemplate.opsForValue().set(key, value, 1, TimeUnit.MINUTES);

    }

 

    // 存儲普通對象操作

 

    /**

     * 存入普通對象

     *

     * @param key 鍵

     * @param value 值

     * @param timeout 有效期,單位秒

     */

    public static void set(final String key, final Object value, final long timeout) {

 

        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);

    }

 

    /**

     * 獲取普通對象

     *

     * @param key 鍵

     * @return 對象

     */

    public static Object get(final String key) {

 

        return redisTemplate.opsForValue().get(key);

    }

 

    // 存儲Hash操作

 

    /**

     * 往Hash中存入數據

     *

     * @param key Redis鍵

     * @param hKey Hash鍵

     * @param value 值

     */

    public static void hPut(final String key, final String hKey, final Object value) {

 

        redisTemplate.opsForHash().put(key, hKey, value);

    }

 

    /**

     * 往Hash中存入多個數據

     *

     * @param key Redis鍵

     * @param values Hash鍵值對

     */

    public static void hPutAll(final String key, final Map<String, Object> values) {

 

        redisTemplate.opsForHash().putAll(key, values);

    }

 

    /**

     * 獲取Hash中的數據

     *

     * @param key Redis鍵

     * @param hKey Hash鍵

     * @return Hash中的對象

     */

    public static Object hGet(final String key, final String hKey) {

 

        return redisTemplate.opsForHash().get(key, hKey);

    }

 

    /**

     * 獲取多個Hash中的數據

     *

     * @param key Redis鍵

     * @param hKeys Hash鍵集合

     * @return Hash對象集合

     */

    public static List<Object> hMultiGet(final String key, final Collection<Object> hKeys) {

 

        return redisTemplate.opsForHash().multiGet(key, hKeys);

    }

 

    // 存儲Set相關操作

 

    /**

     * 往Set中存入數據

     *

     * @param key Redis鍵

     * @param values 值

     * @return 存入的個數

     */

    public static long sSet(final String key, final Object... values) {

        Long count = redisTemplate.opsForSet().add(key, values);

        return count == null ? 0 : count;

    }

 

    /**

     * 刪除Set中的數據

     *

     * @param key Redis鍵

     * @param values 值

     * @return 移除的個數

     */

    public static long sDel(final String key, final Object... values) {

        Long count = redisTemplate.opsForSet().remove(key, values);

        return count == null ? 0 : count;

    }

 

    // 存儲List相關操作

 

    /**

     * 往List中存入數據

     *

     * @param key Redis鍵

     * @param value 數據

     * @return 存入的個數

     */

    public static long lPush(final String key, final Object value) {

        Long count = redisTemplate.opsForList().rightPush(key, value);

        return count == null ? 0 : count;

    }

 

    /**

     * 往List中存入多個數據

     *

     * @param key Redis鍵

     * @param values 多個數據

     * @return 存入的個數

     */

    public static long lPushAll(final String key, final Collection<Object> values) {

        Long count = redisTemplate.opsForList().rightPushAll(key, values);

        return count == null ? 0 : count;

    }

 

    /**

     * 往List中存入多個數據

     *

     * @param key Redis鍵

     * @param values 多個數據

     * @return 存入的個數

     */

    public static long lPushAll(final String key, final Object... values) {

        Long count = redisTemplate.opsForList().rightPushAll(key, values);

        return count == null ? 0 : count;

    }

 

    /**

     * 從List中獲取begin到end之間的元素

     *

     * @param key Redis鍵

     * @param start 開始位置

     * @param end 結束位置(start=0,end=-1表示獲取全部元素)

     * @return List對象

     */

    public static List<Object> lGet(final String key, final int start, final int end) {

        return redisTemplate.opsForList().range(key, start, end);

    }

}





c long lPushAll(final String key, final Collection<Object> values) {

        Long count = redisTemplate.opsForList().rightPushAll(key, values);

        return count == null ? 0 : count;

    }

 

    /**

     * 往List中存入多個數據

     *

     * @param key Redis鍵

     * @param values 多個數據

     * @return 存入的個數

     */

    public static long lPushAll(final String key, final Object... values) {

        Long count = redisTemplate.opsForList().rightPushAll(key, values);

        return count == null ? 0 : count;

    }

 

    /**

     * 從List中獲取begin到end之間的元素

     *

     * @param key Redis鍵

     * @param start 開始位置

     * @param end 結束位置(start=0,end=-1表示獲取全部元素)

     * @return List對象

     */

    public static List<Object> lGet(final String key, final int start, final int end) {

        return redisTemplate.opsForList().range(key, start, end);

    }

}

後續跟上redis進階,關注期待哦

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