NoSql數據庫—Redis

1.NoSql數據庫

1.1 what(什麼是NoSQL數據庫)

    NoSql全稱 not only sql ,非關係型數據庫。他採用簡單、高效的數據格式(例如key-value等)將數據存儲於內存中,極大地提高了數據的訪問速度。可以作爲關係型數據庫的一個很好的補充但不能代替關係型數據庫。

1.2 why(爲什麼要使用NoSQL數據庫)

    傳統關係型數據庫一般用來存儲重要信息,應對普通的業務是沒有問題的。但是,隨着互聯網的高速發展,傳統的關係型數據庫在應付超大規模,超大流量以及高併發的時候力不從心。
    爲了解決高併發、高可擴展(集羣)、高可用(不能宕機)、大數據存儲問題而產生的數據庫解決方案,就是NoSql數據庫。

1.3 where(應用場景?)

    Nosql數據庫相較於傳統關係型數據庫,最大的優點就是存儲簡單、訪問速度快
    根據它的特點主要有以下幾點應用:
        緩存
        分佈式集羣架構中的session分離
        任務隊列(秒殺、搶購、12306等等)
        應用排行榜(SortedSet)
        網站訪問統計
        數據過期處理(expire)

1.4 How(如何使用?)

    接下來的整篇文章,都在介紹如何使用。

關係型數據庫和非關係數據的比較

存儲方式 存儲結構 存儲規範 存儲擴展 查詢方式 事務 性能
關係 二維表 結構化數據(預先定義列結構) 存儲於表中(避免重複、結構清晰) 縱向擴展(操作的性能瓶頸可能涉及多個表,需要通過提高計算機的性能來克服) 結構化的查詢方式(SQL) 支持-遵循ACID規則 低(維護數據的一致性付出了巨大的代價)
非關係 數據集(鍵值,文檔等) 動態結構(適應數據類型、和結構變化) 存儲於數據集中(可重複、易讀寫) 橫向擴展(天然分佈式) key-value查詢(類似map) 支持-遵循BASE原則 高(數據鬆散且存儲於內存中)

常見的關係型數據庫

鍵值(Key-Value)存儲數據庫
相關產品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB。
典型應用:內容緩存,主要用於處理大量數據的高訪問負載。
數據模型:一系列鍵值對
優勢:快速查詢
劣勢:存儲的數據缺少結構化

列存儲數據庫
相關產品:Cassandra, HBase, Riak
典型應用:分佈式的文件系統
數據模型:以列簇式存儲,將同一列數據存在一起
優勢:查找速度快,可擴展性強,更容易進行分佈式擴展
劣勢:功能相對侷限

文檔型數據庫
相關產品:CouchDB、MongoDB
典型應用:Web應用(與Key-Value類似,Value是結構化的)
數據模型:一系列鍵值對
優勢:數據結構要求不嚴格
劣勢:查詢性能不高,而且缺乏統一的查詢語法

圖形(Graph)數據庫
相關數據庫:Neo4J、InfoGrid、Infinite Graph
典型應用:社交網絡
數據模型:圖結構
優勢:利用圖結構相關算法。
劣勢:需要對整個圖做計算才能得出結果,不容易做分佈式的集羣方案。

2.Reids

2.1 簡介

    Redis是用C語言開發的一個開源的高性能鍵值對(key-value)數據庫(nosql),應用在緩存。它通過提供多種鍵值數據類型來適應不同場景下的存儲需求,目前爲止Redis支持的鍵值數據類型有5種
    如下:
        字符串類型 (String)
        散列類型(hash)
        列表類型(List)
        集合類型(set)
        有序集合類型(SortedSet)

2.2 安裝(單機)

1>下載

官網地址:http://redis.io/

2.安裝c語言編譯環境gcc

 yum -y install gcc-c++

3.上傳tar包,解壓縮 tar-zxvf 目錄
4.進行編譯 : cd到解壓目錄 ,輸入命令 make
5.執行安裝(指定安裝目錄)

make install PREFIX=/usr/local/redis	

在這裏插入圖片描述
6.進入安裝目錄,查看是有bin目錄存在

2.3 服務/客戶端的連接、關閉

服務端-前端啓動:

		bin目錄下: ./redis-server 

在這裏插入圖片描述
這種啓動方式後我們就不能進行其他的操作了, Ctrl+C 即可退出。

服務端-後臺啓動(推薦):
第一步:把解壓目錄中的/redis.conf複製到安裝目錄/usr/local/redis/bin目錄下
第二步:使用vim命令修改redis.conf配置文件 將daemonize no修改爲daemonize yes
在這裏插入圖片描述
第三步:輸入啓動命令 (bin目錄下)

	   ./redis-server redis.conf

第四步:檢查redis進程

		ps -ef|grep redis

客戶端的啓動
1> 使用Redis-cli建立連接:

        bin目錄下: ./redis-cli 

    默認連接localhost運行在6379端口的redis服務。

		完整命令如下:./redis-cli -h 192.168.25.131 -p 6379

在這裏插入圖片描述

2>使用redis的桌面程序建立連接
    下載安裝Redis-Deskop-manager即可,這裏就不演示了。

退出客戶端cli 連接
    第一種:
        [root@localhost bin]# ./redis-cli
        127.0.0.1:6379> quit
    第二種:
        [root@localhost bin]# ./redis-cli
        127.0.0.1:6379> exit
    第三種:CTR+C

退出redis服務
    第一種:通過連接上客戶端進行關閉,使用shutdown 命令。
在這裏插入圖片描述
    第二種:使用 kill 命令。
        找到對應的redis的進程id 然後使用命令:(pid爲進程id) kill -9 pid

2.4 常用的數據類型

1>String

命令 格式
設置值 set key value
獲取值 get key
設置獲取值(返回該值的原始值) getset key value
刪除數據(通用) del key
遞增1 incr key
遞增指定長度 incrby key 遞增值
遞減1 decr key
遞增指定長度 decrby key 遞增值
追加字符串(返回追加後的長度) append key value
查詢所有key(通用) keys *
判斷key是否存在(1,0) exists key

在這裏插入圖片描述

2>Hash

命令 格式
設置值 [多個] hset key field value [field1 value1 field2 valued…]
獲取值 hget key field
獲取值 [多個] hmget key field [field1 field2…]
獲取所有的field value hgetall key
刪除指定field hdel key field
刪除指定key(通用) del key
遞增/減(num的正負) hincr key field num
判斷field是否存在 hexits key field
獲取key中field的個數 hlen key
獲取key中所有的field hkeys key
獲取key中所有的value hvals key

在這裏插入圖片描述

3>List

List是有順序可重複(數據結構中的:雙鏈表,隊列)
可作爲鏈表 ,從左添加元素  也可以從右添加元素。
命令 格式
插入(左/右) lpush/rpush key value[value1 value2 …]
查看 lrange key start end (start:從0開始,end可以爲負數,表示倒數第幾個,0 -1表示查看所有)
彈出(刪除) lpop/rpop key (從左/右刪除,並返回被刪除的元素)
獲取個數 llen key
添加如果key存在 lpushx/rpushx key value [value1 value2 …]
刪除(從哪開始刪除幾個value) lrem key num value 例如:lrem key 2 1 表示從左邊開始刪除2個1,若num爲0則表示全部刪除、num爲負數 表示從右開始刪除]
插入到指定位置 lset key index value (注意從0開始)

在這裏插入圖片描述

4>Set

命令 格式
添加 sadd key value1 [value2 value3…]
刪除 srem key value1 [value2 value3…]
查看 smembers key
判斷是否存在 sismember key value
差級運算 sdiff key1 key2 (key2相對於key1的差, 結果和key1、key2順序有關)
交集運算 sinter key1 key2
並集運算 sunion key1 key2
得到元素的數量 scard key
隨機返回指定數量成員 srandmember key [count] (不寫count默認返回一個)
設置新集合保存差值、並集、交集 sdiffstore/sinterstore/sunionstore key key1 key2

在這裏插入圖片描述

5>ZSet

有順序,不能重複,如果重複會覆蓋,適合做排行榜
命令 格式
添加 zadd key 分數1 值1 分數2 值2 …
獲取分數 zscore key value
獲取value的數量 zcard key
範圍查找 zrange/zrevrange key start end [withscores] (分數可選擇是否顯示,range從小到大,rerange 從大到小)
刪除 zrem key value1 [value2 value3 …]
按照排名的順序刪除 zremrangebyrank key start end
按照分數範圍刪除 zremrangebyscore key 分數1 分數2
統計分數之間的value個數 zcount key 分數1 分數2 (注意分數1>=分數2)
添加分數 zincrby key 分數 value

2.5通用操作

命令 格式
獲取所有的key keys *
判斷key是否存在 exists key
key重命名 rename old new
刪除key del key [key1 key2 …]
設置key的過期時間 expire key time (time : 0 負數,可以理解爲立刻刪除)
查看當前key所剩時間 ttl key (-1表示永久,-2表示不存在)
持久化key persist key (ttl查看時間爲-1)
查看當前key的類別 type key
清空當前庫 full all

2.7Reids特性

1>多數據庫

Redis中共有16個數據庫,索引從0開始,默認是選擇第0個
        切換數據庫: select index[0-15]
        移動到某庫:move key index

2>事務機制

    相比於傳統的關係型數據庫來說,Redis的事務並不突出,所以瞭解即可。
        開啓:multi
        提交:exec
        回滾:discard

3>Redis持久化

    Redis的高性能源於其數據保存於內存中,所以存取都是相當快,但是當斷電時,內存中的數據便會丟失,此時我們需要將數據持久化 內存->硬盤,下次啓動的時候,redis會依據持久化的信息做數據恢復。

1.RDB   快照形式  (定期將當前時刻的數據保存磁盤中)會產生一個dump.rdb文件
	特點:會存在數據丟失,性能較好,數據備份。
2.AOF   append only file ,日誌形式 (所有對redis的操作命令記錄在aof文件中),恢復數據,重新執行一遍即可。
	特點:每秒保存,數據比較完整,耗費性能。	

RDB:快照模式默認開啓,默認會將dump.rdb文件保存在redis安裝目錄根目錄下。
     優點:
        1.只包含一個文件
        2.性能最大化
    缺點:
        1.指定間隔保存,宕機時總有來不及保存的文件。
        2.如果指定間隔時間過長,保存的停頓時間很大(Reids是單線程的)

在redis.conf中配置RDB的保存時間間隔:
在這裏插入圖片描述
AOF:是採取日誌記錄的方式、可以每秒,每次修改,進行數據持久化。
     優勢:
          1.數據安全性高,數據丟失概率小。
          2.採用追加寫入,日誌過大,自動重寫(瘦身)
          3.格式清晰,易於修改日誌文件
     劣勢:
        文件大,持久化次數頻繁、運行效率低於RDB
修改redis.conf 配置文件,開啓AOF
在這裏插入圖片描述
主要是修改:
     1.開啓aof appendobly yes
     2.appendsync 選中同步策略, always或者eyerysec
     修改後需要停掉redis,重啓服務。

注意:默認使用rdb方式,但是如果兩都開啓了,會使用aof

3.Jedis

Jedis即:Redis的Java客戶端API,使用方式也很簡單

			<!-- Redis客戶端 -->
			<dependency>
				<groupId>redis.clients</groupId>
				<artifactId>jedis</artifactId>
				<version>xxxxxxx</version>
			</dependency>

3.1常用API

	// string類型操作
	@Test
	public void string_test() {
		// 第一步:創建一個Jedis對象。需要指定服務端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis對象操作數據庫,每個redis命令對應一個方法。
		// 添加設置字符串
		jedis.set("hello", "word");
		String result = jedis.get("hello");
		System.out.println(result); // world
		// 添加數字,自增長
		jedis.set("id", "1");
		String id = jedis.get("id");
		System.out.println(id); // 1
		System.out.println(jedis.incr("id")); // 2
		System.out.println(jedis.get("id")); // 2
		// 第三步:關閉Jedis
		jedis.close();
	}
     
     //hash類型的操作
	@Test
	public void hash_test() {
		// 第一步:創建一個Jedis對象。需要指定服務端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis對象操作數據庫,每個redis命令對應一個方法。
		// 添加map的redis的hash中
		Map<String, String> map = new HashMap<>();
		map.put("name", "faker");
		map.put("grade", "100");
		jedis.hmset("skt", map);
		// 獲取指定field值
		System.out.println(jedis.hget("skt", "name")); // faker
		// 獲取個field對應的值
		jedis.hmget("skt", "name", "grade").forEach(System.out::println); // faker 100
		// 設置增長
		System.out.println(jedis.hincrBy("skt", "grade", 20)); // 120
		jedis.close();
	}
    
    // list類型的操作
	@Test
	public void list_test() {
		// 第一步:創建一個Jedis對象。需要指定服務端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis對象操作數據庫,每個redis命令對應一個方法。
		// 分別從左右添加
		jedis.lpush("list", "1", "2", "3");
		jedis.rpush("list", "x", "y", "z");
		// lrange 獲取指定範圍的值
		jedis.lrange("list", 0, -1).forEach(System.out::println); // 3 2 1 x y z
		// pop 彈出,刪除指定值
		System.out.println(jedis.rpop("list")); // z
		// lset 在指定位設置指定值
		jedis.lset("list", 0, "first");
		jedis.lrange("list", 0, -1).forEach(System.out::println); // first 2 1 x y
		jedis.close();
	}
	
	// set類型的操作
	@Test
	public void set_test() {
		// 第一步:創建一個Jedis對象。需要指定服務端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis對象操作數據庫,每個redis命令對應一個方法。
		// sadd添加值
		jedis.sadd("set", "1", "faker", "2");
		// smembers獲取所有值
		jedis.smembers("set").forEach(System.out::println); // 2 faker 1
		// srem 刪除指定value
		jedis.srem("set", "1");
		// sismember判斷指定vlaue是否存在
		System.out.println(jedis.sismember("set", "1")); // false
		jedis.close();
	}
	
	// zset類型的操作
	@Test
	public void zset_add() {
		// 第一步:創建一個Jedis對象。需要指定服務端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis對象操作數據庫,每個redis命令對應一個方法。
		Map<String, Double> zset = new HashMap<>();
		zset.put("faker", 100d);
		zset.put("clearlove", 99d);
		zset.put("uzi", 99d);
		// 向zset中插入數據
		jedis.zadd("zset", zset);
		// 獲取zset中的所有數據
		Set<Tuple> withScores = jedis.zrangeWithScores("zset", 0, -1);
		withScores.forEach(e -> {
			System.out.println(e.getElement() + "-------" + e.getScore());
			// clearlove-------99.0 uzi-------99.0 faker-------100.0
		});
		// 獲取指定value的分數
		System.out.println(jedis.zscore("zset", "faker")); // 100.0
		jedis.close();
	}

    通過上述代碼可以看出,使用Jedis操作Reids首先要獲取連接對象(Jedis),這和傳統的數據庫獲取connection對象是一樣的,Jedis也爲我們提供了連接池的方式,在程序中更推薦大家使用連接池方式。

	@Test
	public void testJedisPool() throws Exception {
		// 第一步:創建一個JedisPool對象。需要指定服務端的ip及端口。
		JedisPool jedisPool = new JedisPool("192.168.25.131", 6379);
		// 第二步:從JedisPool中獲得Jedis對象。
		Jedis jedis = jedisPool.getResource();
		// 第三步:使用Jedis操作redis服務器。
		jedis.set("jedis", "test");
		String result = jedis.get("jedis");
		System.out.println(result); //jedispool
		// 第四步:操作完畢後關閉jedis對象,連接池回收資源。
		jedis.close();
		// 第五步:關閉JedisPool對象。
		jedisPool.close();
	}

3.2 Spring整合Redis

Redis和Spring的整合十分的簡單,我們只需要使用Spring容器管理JedisPool就可以了

1.首先加入相關的spring、jedis依賴

        <!--此處爲了方便直接引入springmvc的配置文件-->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>4.3.16.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.9.0</version>
		</dependency>

2.配置

	<!-- 配置redis連接池 -->
	<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
		<constructor-arg name="host" value="192.168.25.131"></constructor-arg>
		<constructor-arg name="port" value="6379"></constructor-arg>
	</bean>

3.測試

@Test
	public void redis_spring_test() {
		// 1.首先加載spring的配置文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		// 2.獲取連接池對象
		JedisPool pool = applicationContext.getBean(JedisPool.class);
		// 3.獲取Jedis對象
		Jedis jedis = pool.getResource();
		jedis.set("hello", "world");
		System.out.println(jedis.get("hello")); // world
		jedis.close();
		pool.close();
	}

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