REDIS基礎學習筆記
一. 背景說明
學習每一種新技術之前,我都會盡量提醒自己從這三個方面依次遞進的去學:是什麽,能幹嘛?為什麽用它?怎麽用?
Redis是什麽?一項基於分布式緩存的nosql數據庫技術。能幹嘛?做分布式緩存唄。
為什麽用它?一般來說,每一項新技術的出現,都有其歷史背景及使命(要解決的問題),技術來源於問題。為什麽已經有了傳統的關系型數據庫,還要非關系型數據庫幹啥?毋庸置疑,肯定是原有的老技術有其無法避免的缺點及弊端,即使很有可能總體來說它已經很優秀了。傳統的關系型數據庫,如Oracle、Mysql、SQLServer、DB2,基本上都是把數據主要存放位置放在磁盤上,在一些大數據量,高並發的情況下,磁盤的讀寫速度已經無法滿足需求了,我們迫切需要一個基於更快的物理硬件如內存的數據庫。於是Redis就應運而生了。
二. 用法
2.1 安裝和啟動
首先需要註意下的是,據說Redis在Windows Server中的性能表現要比Linux中差很多。所以,條件允許的話,盡可能的選擇Linux平臺。如果選擇了Linux平臺的話,需要另外註意的一個事情是:Redis是用C語言編寫的,而我們下載的Redis一般源碼安裝程序,所以在這之前你需要確保系統裏有合適的編譯器。gcc或gcc-c++都行,我的系統(CentOS7)裏是之前自己都安裝了:
[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
沒有的話先自行安裝下:
yum install gcc gcc-c++
環境都準備好了之後就可以用下載下來的文件開始安裝了:
解壓
[root@qingxin software]# tar -zxvf redis-4.0.9.tar.gz
進入到解壓出來的目錄裏面,編譯
[root@qingxin redis-4.0.9]# make
安裝到指定目錄
[root@qingxin redis-4.0.9]# make PREFIX=/usr/local/redis-4.0.9/ install
復制配置文件到安裝目錄
[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
檢查是否啟動成功:
[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中要想直接操作數據庫都需要通過這類接口。
- 單實例連接
首先說明下,因為還沒說其他數據類型,所以暫時只用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了:
連接池連接
連接池方式可以實現對連接的共享和復用,以提高連接資源的利用率。@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(); } } }
測試結果:
驗證一下寫入是否成功:
整合Spring
首先第一步肯定是把Spring核心該導的包都導入進來了:
然後就可以寫測試代碼做測試了:
ApplicationContext.xml
<!-- 連接池配置 --> <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>
這種東西還是建議本地保存一份,用的時候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 有序集合 有序不允許重復
這裏我們不扣概念,重點關註命令怎麽用。
- 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持久化及主從復制
兩種持久化方式
RDB:
間隔固定時間去持久化一次
速度較快
AOF:
實時保存
大大拖慢redis系統的速度,比較雞肋。適用於特定情形。
使用方法:
修改配置文件,redis.conf 。 默認的rdb模式,存儲的數據都在dump.rdb文件裏面。
配置文件裏appendonly 項為 no . 使用aof模式,把它改成yes,數據默認保存在
appendonly.aof文件裏面。然後重啟一下就行了:./redis-server redis.conf主從復制
和前面說的兩種持久化方式相關,因為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以驗證備份是否正常。
REDIS基礎學習筆記