Redis 教程
Redis 教程
Redis 概述
Redis(Remote Dictionary Server),即遠程字典服務。是一個開源的使用 ANSI C 語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value 數據庫,并提供多種語言的 API。
與 memcached 一樣,為了保證效率,數據都是緩存在內存中。區別的是 redis 會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎上實現了 master-slave (主從) 同步。
Redis 能該干什么?
- 內存存儲、持久化,內存是斷電即失的,所以需要持久化(RDB、AOF)
- 高效率、用于高速緩沖
- 發布訂閱系統
- 地圖信息分析等
Redis 安裝
這里介紹 Docker 的安裝方式:
# 啟動 redis 服務
docker run -d -p 6379:6379 --name redis redis:latest
# 查看服務是否開啟
docker ps
# 停止正在運行的 redis 服務
docker stop redis
# 重啟 redis 服務
docker start redis
# 訪問容器
docker exec -it redis /bin/bash
# 使用容器內客戶端測試連接
redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set name locke
OK
127.0.0.1:6379> get name
"locke"
127.0.0.1:6379> keys * # 查看當前數據庫中所有的 key
127.0.0.1:6379> flushdb # 清空當前數據庫
127.0.0.1:6379> flushall # 清空全部數據庫的內容
127.0.0.1:6379> exit # 退出客戶端
# 使用 redis 官方提供的性能測試工具
# 測試:100 個并發連接,100000 請求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
五大數據類型
Redis 是一個開源、內存存儲的數據結構服務器,可用作數據庫、高速緩存和消息隊列代理。它支持多種類型的數據結構,如:字符串 (strings)、哈希表 (hashes)、列表 (lists)、集合 (sets)、有序集合 (sorted sets) 與范圍查詢,bitmaps,位圖, hyperloglogs,地理空間 (geospaial),索引半徑查詢等數據類型。內置復制、Lua 腳本、LRU 驅動時間、事務以及不同級別磁盤持久化功能,同時通過 Redis Sentinel 提供高可用,通過 Redis Cluster 提供自動分區。
String
127.0.0.1:6379> set key1 vl # 設置值
127.0.0.1:6379> get key1 # 獲取值
127.0.0.1:6379> keys * # 獲得所有的 key
127.0.0.1:6379> exists key1 # 判斷某一個 key 是否存在
127.0.0.1:6379> strlen key1 # 獲取字符串的長度
127.0.0.1:6379> set user:1 {name:zhangsan,age:30}
List
Redis 列表是最簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。一個列表最多可以包含 232 - 1 個元素(4294967295,每個列表超過 40 億個元素)。
正如圖 Redis 中 List 是可以進行雙端操作的,所以命令也就分為了 LXXX 和 RLLL 兩類,有時候 L 也表示 List 例如 LLEN
127.0.0.1:6379> lpush list one # 將一個值或者多個值,插入到列表頭部(左邊插入)
127.0.0.1:6379> lpush list two
127.0.0.1:6379> lpush list three
127.0.0.1:6379> rpush list right # 將一個值或者多個值,插入到列表尾部(右邊插入)
127.0.0.1:6379> lpop list # 移除list的第一個元素
127.0.0.1:6379> lpop list 2 # 移除list的前兩個元素
127.0.0.1:6379> rpop list 1 # 移除list的最后一個元素
127.0.0.1:6379> lrange list 0 -1 # 獲取 list 中的值
127.0.0.1:6379> lrange list 0 1 # 通過區間獲取具體的值
127.0.0.1:6379> lindex list 2 # 通過下標獲得 list 中的某一個值
127.0.0.1:6379> llen list # 返回列表的長度
127.0.0.1:6379> lrem list 1 one # 移除 list 集合中指定個數的 value,精確匹配
總結:
- 它實際上是一個鏈表,before node after ,left , right 都可以插入值
- 如果 key 不存在,創建新的鏈表
- 如果 key 存在,新增內容
- 如果移除了所有值,空鏈表,也代表不存在
- 在兩邊插入或者改動值,效率最高,中間元素相對來說效率會低一點
事務
Redis 事務本質:一組命令的集合。一個事務中的所有命令都會被序列化,在事務執行過程中,會按照順序執行。
-
Redis 事務沒有隔離級別的概念。
-
所有的命令在事物中,并沒有直接被執行,只有發起執行命令的時候才會執行。
-
redis 單條命令是保證原子性的,但是事務不保證原子性
127.0.0.1:6379> multi # 開啟事務
OK
127.0.0.1:6379(TX)> set k1 v1 # 命令入隊
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec # 執行事務
1) OK
2) OK
3) "v2"
4) OK
Jedis
使用 Java 來操作 Redis,Jedis 是 Redis 官方推薦使用的 Java 連接 redis 的客戶端的開發工具,使用 java 操作 redis 中間件。
- 導入對應的依賴
<dependencies>
<!--導入jedis的包-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<!--fastjson 存一些數據用的-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.48</version>
</dependency>
</dependencies>
- 編碼測試:
- 連接數據庫
- 操作命令
- 斷開連接
package com.jihu;
import redis.clients.jedis.Jedis;
public class TestPing {
public static void main(String[] args) {
// 1. new jedis 對象即可
Jedis jedis = new Jedis("192.168.56.130", 6379);
jedis.auth("123456");
// jedis 所有的命令就是我們之前學習的所有指令
System.out.println(jedis.ping());
}
}
- 事務的操作
package com.jihu;
import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class TestTX {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.56.130",6379);
jedis.auth("123456");
jedis.flushDB();
JSONObject jsonObject = new JSONObject();
jsonObject.put("hello","world");
jsonObject.put("name","jihu");
// 開啟事務
Transaction multi = jedis.multi();
String result = jsonObject.toJSONString();
jedis.watch(result) // 給 result 加樂觀鎖
try {
multi.set("user1",result);
multi.set("user2",result);
int i = 1/0; // 代碼拋出異常,事務執行失敗
multi.exec(); // 執行事務
} catch (Exception exception) {
multi.discard(); // 放棄事務
exception.printStackTrace();
}finally {
System.out.println(jedis.get("user1"));
System.out.println(jedis.get("user2"));
jedis.close(); // 關閉連接
}
}
}
SpringBoot 整合
SpringBoot 操作數據:spring-data jpa jdbc mongodb redis
說明: 在 SpringBoot 2.x 之后,原來使用的 jedis 被替換為了 lettuce:
- jedis : 采用的直連,多個線程操作的話,是不安全的,如果想要避免不安全的,使用 jedis pool 連接池! 更像 BIO 模式
- lettuce : 采用 netty,實例可以再多個線程中進行共享,不存在線程不安全的情況!可以減少線程數據了,更像 NIO 模式
SpringBoot 整合 Redis 的具體操作如下:
- 構建 SpringBoot 項目,導入依賴

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置連接:
application.yaml
spring:
data:
redis:
## 單機模式
host: 127.0.0.1 # 地址
port: 6379 # 端口
# 通用配置
username: # 用戶名
password: # 密碼
database: 0 # 指定數據庫序號
connect-timeout: 1000 # 連接超時時間(毫秒)
timeout: 1000 # 操作超時時間(毫秒)
client-name: # 客戶端名稱(不知道干嘛用的)
client-type: lettuce # 驅動類型
# 連接池配置
lettuce:
pool:
min-idle: 1 # 最小空閑連接(默認0)
max-idle: 8 # 最大空閑連接(默認8)
max-active: 16 # 最大連接數(默認8,使用負值表示沒有限制)
max-wait: -1ms # 最大阻塞等待時間(默認-1,負數表示沒限制)
- 測試
@SpringBootTest
class Springboot10RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
// redisTemplate: 操作不同的數據類型,api和我們的指令是一樣的
// redisTemplate.opsForValue(): 表示操作字符串 類似String
// redisTemplate.opsForList(): 表示操作List ,類似list
redisTemplate.opsForList();
redisTemplate.opsForValue().set("mykey","jihu");
System.out.println(redisTemplate.opsForValue().get("mykey"));
// 除了基本的操作,我們常用的方法都可以直接通過 redisTemplate 操作,比如事務和基本的 CRUD
}
}
- RedisUtil 配置 (CRUD 操作 string | map | list | set)
@Service
public class RedisUtil {
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 將 list 放入緩存
*
* @param key 鍵
* @param value 值
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 獲取 list 緩存的內容
*
* @param key 鍵
* @param start 開始
* @param end 結束 0 到 -1 代表所有值
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
- 再測試
@SpringBootTest
class Springboot10RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedisUtil redisUtil;
@Test
void contextLoads() throws JsonProcessingException {
// redisTemplate: 操作不同的數據類型,api 和我們的指令是一樣的
// redisTemplate.opsForValue(): 表示操作字符串 類似 String
// redisTemplate.opsForList(): 表示操作 List ,類似 list
redisTemplate.opsForValue().set("user", "locke");
System.out.println(redisTemplate.opsForValue().get("user"));
// 除了基本的操作,我們常用的方法都可以直接通過 redisTemplate 操作,比如事務和基本的 CRUD
}
// 使用 redisUtil 對 redis 操作進行封裝,使用起來更加簡潔
@Test
public void testRedis() {
redisUtil.lSet("user", "lockegogo");
// 獲取 key 的值
System.out.println(redisUtil.lGet("user", 0, -1));
}
}
浙公網安備 33010602011771號