REDIS基礎學習筆記

一. 背景說明

學習每一種新技術以前,我都會盡可能提醒本身從這三個方面依次遞進的去學:是什麼,能幹嗎?爲何用它?怎麼用? Redis是什麼?一項基於分佈式緩存的nosql數據庫技術。能幹嗎?作分佈式緩存唄。 爲何用它?通常來講,每一項新技術的出現,都有其歷史背景及使命(要解決的問題),技術來源於問題。爲何已經有了傳統的關係型數據庫,還要非關係型數據庫幹啥?毋庸置疑,確定是原有的老技術有其沒法避免的缺點及弊端,即便頗有可能整體來講它已經很優秀了。傳統的關係型數據庫,如Oracle、Mysql、SQLServer、DB2,基本上都是把數據主要存放位置放在磁盤上,在一些大數據量,高併發的狀況下,磁盤的讀寫速度已經沒法知足需求了,咱們迫切須要一個基於更快的物理硬件如內存的數據庫。因而Redis就應運而生了。 怎麼用?後面天然會說,在這以前先按正常節奏一步步的瞭解並同時學習用法。前端

二. 用法

2.1 安裝和啓動

首先須要注意下的是,聽說Redis在Windows Server中的性能表現要比Linux中差不少。因此,條件容許的話,儘量的選擇Linux平臺。若是選擇了Linux平臺的話,須要另外注意的一個事情是:Redis是用C語言編寫的,而咱們下載的Redis通常源碼安裝程序,因此在這以前你須要確保系統裏有合適的編譯器。gcc或gcc-c++都行,個人系統(CentOS7)裏是以前本身都安裝了:java

[root@qingxin ~]# rpm -qa gcc*
gcc-4.8.5-28.el7_5.1.x86_64
gcc-c++-4.8.5-28.el7_5.1.x86_64

沒有的話先自行安裝下:linux

yum install gcc gcc-c++

環境都準備好了以後就能夠用下載下來的文件開始安裝了: 解壓c++

[root@qingxin software]# tar -zxvf redis-4.0.9.tar.gz

進入到解壓出來的目錄裏面,編譯redis

[root@qingxin redis-4.0.9]# make

安裝到指定目錄spring

[root@qingxin redis-4.0.9]# make PREFIX=/usr/local/redis-4.0.9/ install

複製配置文件到安裝目錄sql

[root@qingxin redis-4.0.9]# cp redis.conf /usr/local/redis-4.0.9/bin/

到這裏咱們的Redis安裝基本就算完成了,接下來能夠嘗試啓動Redis了。 關於Redis的啓動主要是要知道兩種啓動方式:前端啓動和後端啓動。Redis默認使用前端啓動方式,這樣當你運行redis-server啓動了以後,它會一直卡在哪裏,必須另外開一個session使用redis-cli去訪問它,這樣挺麻煩的。因此推薦後端啓動方式:修改redis.conf配置文件,把daemonize由no改爲yes,這樣redis-server就能夠在後臺跑着了。(爲了方便建議將Redis安裝目錄加入PATH裏)數據庫

[root@qingxin bin]# redis-server redis.conf

檢查是否啓動成功:windows

[root@qingxin bin]# ps -aux|grep redis-server

訪問直接使用redis-cli,帶密碼的話使用-a參數。關閉也是使用redis-cli,只是多加一個shutdown。後端

2.2 Jedis的使用

Redis自己的使用來說主要就是一堆命令。在說哪些以前,先說說Jedis。Jedis對於redis就相似於JDBC於Mysql、Oracle。都是對數據庫訪問的接口,在Java中要想直接操做數據庫都須要經過這類接口。

  1. 單實例鏈接 首先說明下,由於還沒說其餘數據類型,因此暫時只用String類型的作測試。這一個和下一個例子咱們只引入jedis,commons-pool,junit作測試:

單實例鏈接比較簡單,作完以後,咱們會看下使用鏈接池方式怎麼寫。

package com.zqx;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class TestJedis {
@Test
public void testJedisSingle(){
Jedis jedis = new Jedis("192.168.15.142",6379);
jedis.set("username","zqx");
String user = jedis.get("username") + "," + jedis.get("country");
System.out.println(user);
jedis.close();
}
}

這裏須要注意,由於我這裏的測試程序是跑在windows系統裏的。而個人redis-server運行在個人Linux虛擬機裏,因此要想看到測試效果,須要先確保能從windows訪問到虛擬機裏的redis。要作到這一點,須要注意兩個問題: 一. redis.conf裏的bind項改爲0.0.0.0以讓任意IP都能訪問 二. Linux的防火牆開啓對redis默認6379端口的訪問,

[root@qingxin bin]# iptables -A INPUT -ptcp --dport 6379 -j ACCEPT

由於centosos7默認使用firewalld管理了,個人系統是centos7的,因此用下面這個

[root@qingxin bin]# firewall-cmd --permanent --zone=public --add-port=6379/tcp

改完記得重啓一下服務:

[root@qingxin bin]# systemctl restart firewalld

[root@qingxin bin]# service iptables restart

作完這些本地測試下可否正常鏈接:

代碼測試結果:

驗證一下數據是否寫入到redis-server了:

  1. 鏈接池鏈接 鏈接池方式能夠實現對鏈接的共享和複用,以提升鏈接資源的利用率。

    @Test
     public void testJedisPools(){
     	JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
     	//最大鏈接數
     	jedisPoolConfig.setMaxTotal(30);
     	//最大鏈接空閒數,即便沒有任何鏈接也能夠保留的鏈接數
     	jedisPoolConfig.setMaxIdle(2);
    
     	JedisPool jedisPool = new JedisPool(jedisPoolConfig,"192.168.15.142",6379);
    
     	Jedis jedis = null;
     	try{
     		jedis = jedisPool.getResource();
     		jedis.set("username1","zhuqingxin");
     		String user1 = jedis.get("username1")+","+jedis.get("country");
     		System.out.println(user1);
     	}catch (Exception e){
     		throw e;
     	}finally {
     		if(jedis != null){
     			jedis.close();
     		}
     	}
     }

測試結果:

驗證一下寫入是否成功:

  1. 整合Spring 首先第一步確定是把Spring核心該導的包都導入進來了: 而後就能夠寫測試代碼作測試了: ApplicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">

    <!-- 鏈接池配置 -->
     <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
     	<!-- 最大鏈接數 -->
     	<property name="maxTotal" value="30" />
     	<!-- 最大空閒鏈接數 -->
     	<property name="maxIdle" value="10" />
     	<!-- 每次釋放鏈接的最大數目 -->
     	<property name="numTestsPerEvictionRun" value="1024" />
     	<!-- 釋放鏈接的掃描間隔(毫秒) -->
     	<property name="timeBetweenEvictionRunsMillis" value="30000" />
     	<!-- 鏈接最小空閒時間 -->
     	<property name="minEvictableIdleTimeMillis" value="1800000" />
     	<!-- 鏈接空閒多久後釋放, 當空閒時間>該值 且 空閒鏈接>最大空閒鏈接數 時直接釋放 -->
     	<property name="softMinEvictableIdleTimeMillis" value="10000" />
     	<!-- 獲取鏈接時的最大等待毫秒數,小於零:阻塞不肯定的時間,默認-1 -->
     	<property name="maxWaitMillis" value="1500" />
     	<!-- 在獲取鏈接的時候檢查有效性, 默認false -->
     	<property name="testOnBorrow" value="true" />
     	<!-- 在空閒時檢查有效性, 默認false -->
     	<property name="testWhileIdle" value="true" />
     	<!-- 鏈接耗盡時是否阻塞, false報異常,ture阻塞直到超時, 默認true -->
     	<property name="blockWhenExhausted" value="false" />
     </bean>
    
     <!--配置 jedisPool -->
     <bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="close">
     	<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
     	<constructor-arg name="host" value="192.168.15.142"/>
     	<constructor-arg name="port" value="6379"/>
     </bean>

    </beans>

這種東西仍是建議本地保存一份,用的時候copy過來改改就能用了。 TestSpringJedis.java

package com.zqx;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class TestSpringJedis {

	private ApplicationContext applicationContext;

	@Before
	public void init(){
		applicationContext = new ClassPathXmlApplicationContext("classpath:ApplicationContext.xml");
	}

	@Test
	public void testJedisPool(){
		JedisPool pool = (JedisPool) applicationContext.getBean("jedisPool");
		Jedis jedis = null;
		try{
			jedis = pool.getResource();
			jedis.set("username2","11242");
			String user2= jedis.get("username2") + "," + jedis.get("country");
			System.out.println(user2);
		}catch (Exception e){
			throw e;
		}finally {
			if (jedis!=null){
				jedis.close();
			}
		}
	}

}

測試結果:

驗證一下寫入是否成功:

另外,說一下,這裏的鏈接和鏈接池你不關閉,Spring也會幫你關的。 好的,到這裏,Jedis的基礎用法就差很少了,下面看看Redis的數據類型。

2.3 Redis數據類型

總的來講,Redis有5種數據類型: String 字符串 list 列表 hash 哈希 set 集合 無序且不容許重複 zset 有序集合 有序不容許重複 這裏咱們不扣概念,重點關注命令怎麼用。

  1. String類型 其實咱們前面一直用的就是String,主要就是用了set,get命令。再總的走一遍:

Set是賦值,get是取值。getset是先取當前值,再賦值。Del是刪除,更新就再set一次。 除了這些還有一些實用的命令 遞增遞減(incr,decr,incrby,decrby): 追加(append): 獲取長度(strlen): 同時設置獲取多個值(mset,mget): 2 Hash類型 Hash表相似於關係型數據庫裏的一條記錄。一條記錄對應一個Hash類型的key,下面能夠有多個屬性。 基本的hget,hset獲取設置單個field值,hmget,hmset操做多個屬性。Hgetall獲取全部屬性,hdel刪除一個或多個屬性。其餘還有hkeys,hvals只獲取key,只獲取值。 3 List類型 Redis裏面的list相似於LinkedList,就像一個雙向循環鏈表。這個時候對其添加和刪除的操做就有幾種區別,在表頭插入,表尾插入,表頭刪除,表尾刪除。或者其實按它的實際命令來看,咱們能夠也能夠把它當作一個雙向棧,對應的操做就變成了正向入棧,反向入棧,正向出棧,反向出棧了。

192.168.15.142:6379> lpush lkey1 1 2 3
(integer) 3
192.168.15.142:6379> lrange lkey1 0 -1
1) "3"
2) "2"
3) "1"
192.168.15.142:6379> rpush lkey1 4 5 6
(integer) 6
192.168.15.142:6379> lrange lkey1 0 -1
1) "3"
2) "2"
3) "1"
4) "4"
5) "5"
6) "6"
192.168.15.142:6379> llen lkey1
(integer) 6

基礎命令就是lpush,rpush,對應正向入棧,反向入棧。對應的出棧操做就是lpop,rpop,都是相似的就不演示了,llen能夠獲取總數,還有lrem能夠移除元素。其實到這裏已經能發現,redis的命令很多,所有記下來也不容易,但就和學linux命令同樣,咱們不少時候仍是須要用到什麼查什麼,可是基本的一些命令仍是最好能記下來。 須要注意一下的是lrange,我試了下redis裏list好像只能正向遍歷,沒有rrange的說法。lrange的用法,須要本身去試下就明白了,我總結起來是:

格式: lrange key start end
end爲負數表示逆向遍歷,此時start也爲負數且小於end,則按順序遍歷下來。
爲負數還大於end則取不到元素,爲正數則兩邊按本身的索引規則來

最經常使用的是: lrange key 0 -1取全部的元素。 1.1.3.4 Set和Zset類型 這裏有個問題先記一下:redis會自動把中文轉爲Unicode存儲。 Set表示無序集合,ZSet表示有序集合,Zset多一個score的概念。

192.168.15.142:6379> sadd skey1 1 2 3 4 5
(integer) 5
192.168.15.142:6379> smembers skey1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
192.168.15.142:6379> sadd skey1 1 3 4
(integer) 0
192.168.15.142:6379> smembers skey1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
192.168.15.142:6379> sismember skey1 3
(integer) 1
192.168.15.142:6379> sadd skey2 3 4  6 7
(integer) 4
192.168.15.142:6379> sdiff skey1 skey2
1) "1"
2) "2"
3) "5"
192.168.15.142:6379> sinter skey1 skey2
1) "3"
2) "4"
192.168.15.142:6379> sunion skey1 skey2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
192.168.15.142:6379>

Sadd添加,srem移除。Smembers查看全部,sismember判斷是否存在某元素。Sdiff取差集,sinter取交集,sunion取並集。下面繼續簡單說下下有序集合的用法,再也不演示:

zadd zkey1 10 zhangsan 20 lisi 30 wangwu 往有序集合裏面添加元素
zrange zkey1 0 -1 查看有序集合全部元素
zrem zkey1 wangwu
zrange zkey1 0 -1 withscores 帶分數(排名)的查看元素
zrevrange zkey1 0 -1 withscores 帶分數的降序(從大到小)查看元素

能夠看到redis數據類型相關命令不少,但也很簡單很相似。關鍵在於本身去試,去查。

4 Redis通用命令 只說兩個:keys 和 ping。 Keys可使用通配符實現模糊查詢,ping能夠檢查redis-server是否掛掉。

2.4 Redis持久化及主從複製

  1. 兩種持久化方式 RDB: 間隔固定時間去持久化一次 速度較快 AOF: 實時保存 大大拖慢redis系統的速度,比較雞肋。適用於特定情形。 使用方法: 修改配置文件,redis.conf 。 默認的rdb模式,存儲的數據都在dump.rdb文件裏面。 配置文件裏appendonly 項爲 no . 使用aof模式,把它改爲yes,數據默認保存在 appendonly.aof文件裏面。而後重啓一下就好了:./redis-server redis.conf

  2. 主從複製 和前面說的兩種持久化方式相關,由於aof模式不適合主從複製,只適用於rbd模式。 備份原理:

    從服務器發送sync請求命令,主redis發生dump.rdb文件,已經當前未持久化的緩存中全部寫命令,這樣就能保證主從一致。這種方式不適應與aof模式。從redis使用ping命令,聽從心跳機制,檢測主redis是否掛掉了,若是掛掉,則從redis臨時頂替,且從redis此時默認是隻讀的,以保證主從一致。

用法演示:

在同一臺機器上模擬,把dump.rdb文件先刪掉或備份出來,保證沒有歷史數據。拷貝一份redis出來,主redis不須要作更改,從redis的配置文件裏,port修改一下避免衝突,另外取消slaveof項的配置,設置要同步那個主服務器。此時,先啓動主redis,後啓動從redis,在主redis裏面設置一些key,而後shutdown掉。進入從redis-cli,看看主redis裏面set過的key是否可以get以驗證備份是否正常。
相關文章
相關標籤/搜索