Docker入門實踐筆記(三)一篇文章搞懂Docker下安裝Redis,以及Redis與SpringBoot整合
內容
先介紹單機版Redis映象在Docker下的安裝,然後在容器的Redis Shell中進行常用型別String、List、Set、Hash、SortedSet的增刪改查操作測試,最後再結合SpringBoot專案進行簡單的測試。後續會推出哨兵模式(Sentinel,一主二從三哨兵)和叢集模式(Redis Cluster)的安裝和部署,敬請關注。
版本
作業系統: CentOS 7.2 64位
Docker:17.12.1.ce
Redis: 3.2.12
適合人群
linux運維人員,docker運維人員,java人員
說明
轉載請說明出處: ofollow,noindex">Docker入門實踐筆記(三)一篇文章搞懂Docker下安裝Redis,以及Redis與SpringBoot整合
Demo原始碼託管: https://github.com/leo-zz/SpringBootDemo
參考
Docker官方文件: https://hub.docker.com/r/library/redis/
Linux入門實踐筆記(三)——資料盤格式化和和多分割槽掛載
Redis 命令參考: http://redisdoc.com/
前提
伺服器需要安裝Docker CE,未安裝的童鞋請參考 Docker入門實踐筆記(一)——安裝Docker CE ;
此示例將redis的快取持久化到 ~/redis/data
路徑下,如果需要分割槽掛載資料盤的童鞋,請參考 Linux入門實踐筆記(三)——資料盤格式化和和多分割槽掛載 。
步驟
下載Redis映象
使用 docker pull
,從Docker倉庫中下載Redis映象,本示例下載的版本為3.2.12。使用 docker images
檢視已經下載的映象資訊。
#從Docker倉庫中下載Redis映象 [user1@iz8vb62snc6e5cage5yvz9z /]$ sudo docker pull redis:3.2.12 3.2.12: Pulling from library/redis f17d81b4b692: Pull complete b32474098757: Pull complete 8980cabe8bc2: Pull complete 58af19693e78: Pull complete a977782cf22d: Pull complete 9c1e268980b7: Pull complete Digest: sha256:7b0a40301bc1567205e6461c5bf94c38e1e1ad0169709e49132cafc47f6b51f3 Status: Downloaded newer image for redis:3.2.12 #檢視已經下載的映象資訊 [user1@iz8vb62snc6e5cage5yvz9z home]$ sudo docker images REPOSITORYTAGIMAGE IDCREATEDSIZE redis3.2.1287856cc398628 days ago76MB
配置redis.conf
將redis.conf拷貝到 /home/user1/redis/config
路徑下,可以修改此檔案以配置Redis;本示例使用預設配置。
[user1@iz8vb62snc6e5cage5yvz9z config]$ ls redis.conf [user1@iz8vb62snc6e5cage5yvz9z config]$ pwd /home/user1/redis/config
建立Redis容器
使用 docker run
建立Redis容器,然後使用 docker ps
檢視容器的執行情況。
[user1@iz8vb62snc6e5cage5yvz9z redis]$ sudo docker run -p 6379:6379 -v /home/user1/redis/config:/usr/local/etc/redis/redis.conf -v /home/user1/redis/data:/data --name jmsRedis -d redis:3.2.12redis-server /usr/local/etc/redis/redis.conf 14d9c846b6586953c9528a0d6cbfe3257f4a936892e8d8778260a7aaf62b79c7 [user1@iz8vb62snc6e5cage5yvz9z redis]$ sudo docker ps CONTAINER IDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 14d9c846b658redis:3.2.12"docker-entrypoint.s…"15 seconds agoUp 15 seconds0.0.0.0:6379->6379/tcpjmsRedis
建立容器的引數釋義:
-p是指定容器到宿主機的埠對映,這裡使用的是Redis的預設埠號6379,對映為宿主機的6379。
-v是指定容器到宿主機的檔案對映,這裡將Redis容器的持久化資料存放路徑/data對映到宿主機的/home/user1/redis/data;將Redis的配置檔案/usr/local/etc/redis/redis.conf對映到宿主機的/home/user1/redis/config。
--name是指定容器的名稱為jmsRedis。
-d表示在後臺啟動Redis。
redis-server /usr/local/etc/redis/redis.conf 表示啟動指定配置檔案的Redis。
容器內測試
執行docker exec進入容器,由於容器中安裝了Redis,故可以執行redis-cli命令進入Redis shell。
[user1@iz8vb62snc6e5cage5yvz9z redis]$ sudo docker exec -it 14d9c846b658 /bin/bash root@14d9c846b658:/data# redis-cli -h localhost -p 6379 localhost:6379>
測試String型別資料的增刪改查
演示Redis中String型別資料的的設定set、查詢get、刪除del操作。
#將字串值 value 關聯到 key 。如果 key 已經持有其他值, SET 就覆寫舊值,無視型別。 #對於帶有生存時間(TTL)的鍵來,當SET命令成功在這個鍵上執行時,這個鍵原有的TTL將被清除。 #時間複雜度:O(1);返回值:設定操作成功完成時,返回 OK. localhost:6379> set hello leo OK #返回 key 所關聯的字串值。當 key 不存在時,返回 nil ,否則,返回 key 的值。 #如果 key 不是字串型別,那麼返回一個錯誤。時間複雜度:O(1) localhost:6379> get hello "leo" #刪除給定的一個或多個 key 。不存在的 key 會被忽略。返回值:被刪除 key 的數量。 #時間複雜度:O(N), N 為被刪除的 key 的數量。刪除單個字串型別的 key ,時間複雜度為O(1)。刪除單個列表、集合、有序集合或雜湊表型別的 key , 時間複雜度為O(M), M 為以上資料結構內的元素數量。 localhost:6379> del hello (integer) 1 llocalhost:6379> get hello (nil)
測試List型別資料的增刪改查
演示Redis中List型別資料的的插入rpush、範圍查詢lrange、按下標查詢lindex、移除頭元素lpop操作。
#將一個或多個值 value 插入到列表 key 的表尾(最右邊),索引依次遞增。 #時間複雜度:O(1),返回值:rpush後list的長度 localhost:6379> rpush fruit apple (integer) 1 localhost:6379> rpush fruit banana pear orange (integer) 4 #返回列表 key 中指定區間內的元素,區間以偏移量 start 和 stop 指定。下標(index)引數 start 和 stop 都以 0 為底, 也就是說,以 0 表示列表的第一個元素,以 1 表示列表的第二個元素;也可以使用負數下標,以 -1 表示列表的最後一個元素, -2 表示列表的倒數第二個元素,以此類推。#時間複雜度:O(S+N), S 為偏移量 start , N 為指定區間內元素的數量。遍歷1次連結串列拿取所有範圍內的資料。 localhost:6379> lrange fruit 0 -1 1) "apple" 2) "banana" 3) "pear" 4) "orange" #返回列表 key 中,下標為 index 的元素。 時間複雜度O(N),需要遍歷連結串列。 localhost:6379> lindex fruit 2 "pear" #移除並返回列表 key 的頭元素。當 key 不存在時,返回 nil 。 #時間複雜度:O(1),頭元素是指index最小的元素。所有元素的index會隨著pop操作更新 localhost:6379> lpop fruit "apple" localhost:6379> lrange fruit 0 -1 1) "banana" 2) "pear" 3) "orange"
測試SET型別資料的增刪改查
演示Redis中Set型別資料的的插入sadd、集合查詢smembers、判斷成員是否存在sismember、移除成員srem操作。
#將一個或多個 member 元素加入到集合 key 當中,已經存在於集合的 member 元素將被忽略。 #假如 key 不存在,則建立一個只包含 member 元素作成員的集合。當 key 不是集合型別時,返回一個錯誤。 #時間複雜度:O(N), N 是被新增的元素的數量。返回值:被新增到集合中的新元素的數量,不包括被忽略的元素。 localhost:6379> sadd animal tiger (integer) 1 localhost:6379> sadd animal panda (integer) 1 localhost:6379> sadd animal lion (integer) 1 localhost:6379> sadd animal fish (integer) 1 localhost:6379> sadd animal lion (integer) 0 #返回集合 key 中的所有成員。不存在的 key 被視為空集合。 #時間複雜度:O(N), N 為集合的基數。 localhost:6379> smembers animal 1) "panda" 2) "tiger" 3) "fish" 4) "lion" #判斷 member 元素是否集合 key 的成員。時間複雜度:O(1) #如果 member 元素是集合的成員,返回 1 。如果 member 元素不是集合的成員,或 key 不存在,返回 0 。 localhost:6379> sismember animal panda (integer) 1 #移除集合 key 中的一個或多個 member 元素,不存在的 member 元素會被忽略。 #時間複雜度:O(N), N 為給定 member 元素的數量。 #返回值:被成功移除的元素的數量,不包括被忽略的元素。當 key 不是集合型別,返回一個錯誤。 localhost:6379> srem animal panda (integer) 1 localhost:6379> sismember animal panda (integer) 0
測試HASH型別資料的增刪改查
演示Redis中Hash型別資料的的插入hset、集合查詢hgetall、根據Key查詢hget、移除hdel操作。
#將雜湊表 key 中的域 field 的值設為 value 。如果 key 不存在,一個新的雜湊表被建立並進行 HSET 操作。 #如果域 field 已經存在於雜湊表中,舊值將被覆蓋。 #返回值:如果 field 是雜湊表中的一個新建域,並且值設定成功,返回 1 。如果雜湊表中域 field 已經存在且舊值已被新值覆蓋,返回 0 。時間複雜度:O(1) localhost:6379> hset phones mi8 xiaomi (integer) 1 localhost:6379> hset phones v10 honor (integer) 1 localhost:6379> hset phones pro2 smartisan (integer) 1 localhost:6379> hset phones nex vivo (integer) 1 #返回雜湊表 key 中,所有的域和值。在返回值裡,緊跟每個域名(field name)之後是域的值(value),所以返回值的長度是雜湊表大小的兩倍。 #時間複雜度:O(N), N 為雜湊表的大小。 localhost:6379> hgetall phones 1) "mi8" 2) "xiaomi" 3) "v10" 4) "honor" 5) "pro2" 6) "smartisan" 7) "nex" 8) "vivo" #刪除雜湊表 key 中的一個或多個指定域,不存在的域將被忽略。返回值:被成功移除的域的數量. #時間複雜度:O(N), N 為要刪除的域的數量。 localhost:6379> hdel phones pro2 (integer) 1 localhost:6379> hdel phones pro2 (integer) 0 #返回雜湊表 key 中給定域 field 的值。時間複雜度:O(1);返回值:給定域的值,若不存在則返回nil。 localhost:6379> hget phones pro2 (nil) localhost:6379> hget phones mi8 "xiaomi" localhost:6379> hgetall phones 1) "mi8" 2) "xiaomi" 3) "v10" 4) "honor" 5) "nex" 6) "vivo"
測試Sorted set型別資料的增刪改查
演示Redis中Hash型別資料的的插入zadd、範圍查詢zrange、限定score的範圍查詢zrangebyscore、移除zrem操作。
#Sorted Set新增/刪除一個元素的複雜度為log(N),實現的資料結構感覺像是二叉樹 #將一個或多個 member 元素及其 score 值加入到有序集 key 當中。score 值可以是整數值或雙精度浮點數。 #如果某個 member 已經是有序集的成員,那麼更新這個 member 的 score 值,並通過重新插入這個 member 元素,來保證該 member 在正確的位置上。 #時間複雜度:O(M*log(N)), N 是有序集的基數, M 為成功新增的新成員的數量。 #返回值:被成功新增的新成員的數量,不包括那些被更新的、已經存在的成員。 localhost:6379> zadd zphones 1598 vivoZ3 (integer) 1 localhost:6379> zadd zphones 1599 oppoK1 (integer) 1 localhost:6379> zadd zphones 2499 XiaoMi8 (integer) 1 localhost:6379> zadd zphones 1299 SmartisanPro2 (integer) 1 #返回有序集 key 中,指定區間內的成員。其中成員的位置按 score 值遞增(從小到大)來排序。具有相同 score 值的成員按字典序(lexicographical order )來排列。 #以 0 表示有序集第一個成員,以 1 表示有序集第二個成員,支援負數下標,-1 表示最後一個成員,-2 表示倒數第二個成員 #時間複雜度:O(log(N)+M), N 為有序集的基數,而 M 為結果集的基數。 localhost:6379> zrange zphone 0 -1 (empty list or set) localhost:6379> zrange zphones 0 -1 1) "SmartisanPro2" 2) "vivoZ3" 3) "oppoK1" 4) "XiaoMi8" localhost:6379> zrange zphones 0 -1 withscores 1) "SmartisanPro2" 2) "1299" 3) "vivoZ3" 4) "1598" 5) "oppoK1" 6) "1599" 7) "XiaoMi8" 8) "2499" #返回有序集 key 中,所有 score 值介於 min 和 max 之間(包括等於 min 或 max )的成員。有序整合員按 score 值遞增(從小到大)次序排列。 #可選的 LIMIT 引數指定返回結果的數量及區間,注意當 offset 很大時,定位 offset 的操作可能需要遍歷整個有序集,此過程最壞複雜度為 O(N) 時間。 #可選的 WITHSCORES 引數決定結果集是單單返回有序集的成員,還是將有序整合員及其 score 值一起返回。 #min 和 max 可以是-inf和+inf,可以在不知道有序集的最低和最高score值的情況下使用 localhost:6379> zrangebyscore zphones 999 1599 withscores 1) "SmartisanPro2" 2) "1299" 3) "vivoZ3" 4) "1598" 5) "oppoK1" 6) "1599" #移除有序集 key 中的一個或多個成員,不存在的成員將被忽略。當 key 存在但不是有序集型別時,返回一個錯誤。 #時間複雜度:O(M*log(N)), N 為有序集的基數, M 為被成功移除的成員的數量。 #返回值:被成功移除的成員的數量 localhost:6379> zrem zphones SmartisanPro2 (integer) 1 localhost:6379> zrange zphones 0 -1 withscores 1) "vivoZ3" 2) "1598" 3) "oppoK1" 4) "1599" 5) "XiaoMi8" 6) "2499"
搭建SpringBoot測試專案
建立SpringBoot專案
通過IDEA中的Spring Initializr建立SpringBoot專案。
Group和Artifact配置如下。
選擇SpringBoot的版本為1.5.x,並勾選Redis的依賴。
選則專案所在路徑。
專案建立完畢,可以刪除maven wrapper相關的檔案和資料夾。
POM
在建立專案中已經勾選了Redis相關的依賴,不需要再在POM檔案中新增其他依賴
<!-- 可以看到Spring Initailizer已經幫我們引入了redis的依賴 --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
yaml
spring: redis: host: 192.168.1.25 #redis伺服器的IP地址 port: 6379 #redis監聽的埠號
Redis配置類
@Configuration public class RedisConfig { /** * 注入 RedisConnectionFactory */ @Autowired RedisConnectionFactory redisConnectionFactory; /** * 例項化 RedisTemplate 物件 * */ @Bean public RedisTemplate<String, Object> createRedisTemplate() { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); initializeRedisTemplate(redisTemplate, redisConnectionFactory); return redisTemplate; } /** * 設定資料存入 redis 的序列化方式 * */ private void initializeRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory redisConnectionFactory) { redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); redisTemplate.setConnectionFactory(redisConnectionFactory); } /** * 例項化 HashOperations 物件,可以使用 Hash 型別操作 * */ @Bean public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForHash(); } /** * 例項化 ValueOperations 物件,可以使用 String 操作 * */ @Bean public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForValue(); } /** * 例項化 ListOperations 物件,可以使用 List 操作 * */ @Bean public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForList(); } /** * 例項化 SetOperations 物件,可以使用 Set 操作 * */ @Bean public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForSet(); } /** * 例項化 ZSetOperations 物件,可以使用 ZSet 操作 * */ @Bean public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForZSet(); } }
Redis工具類
本示例主要進行Redis中Hash型別資料的操作。
@Component public class RedisHashUtil<T> { @Autowired protected RedisTemplate<String, Object> redisTemplate; @Resource protected HashOperations<String, String, T> hashOperations; private String getRedisKey() { return "REDIS_DEMO"; } /** * 新增 * * @param keykey * @param value 物件 * @param expire 過期時間(單位:秒),傳入 -1 時表示不設定過期時間 */ public void put(String key, T value, long expire) { hashOperations.put(getRedisKey(), key, value); if (expire != -1) { redisTemplate.expire(getRedisKey(), expire, TimeUnit.SECONDS); } } /** * 刪除 * * @param key 傳入key的名稱 */ public void remove(String key) { hashOperations.delete(getRedisKey(), key); } /** * 查詢 * * @param key 查詢的key * @return */ public T get(String key) { return hashOperations.get(getRedisKey(), key); } /** * 獲取當前redis庫下所有value * * @return */ public List<T> getAll() { return hashOperations.values(getRedisKey()); } /** * 查詢查詢當前redis庫下所有key * * @return */ public Set<String> getKeys() { return hashOperations.keys(getRedisKey()); } /** * 判斷key是否存在redis中 * * @param key 傳入key的名稱 * @return */ public boolean isKeyExists(String key) { return hashOperations.hasKey(getRedisKey(), key); } /** * 查詢當前key下快取數量 * * @return */ public long count() { return hashOperations.size(getRedisKey()); } /** * 清空redis */ public void clear() { Set<String> set = hashOperations.keys(getRedisKey()); set.stream().forEach(key -> hashOperations.delete(getRedisKey(), key)); } }
測試類
使用Redis中HASH型別資料結構儲存key-value型別的快取。
@RunWith(SpringRunner.class) @SpringBootTest public class RedisdemoApplicationTests { @Autowired RedisHashUtil<String> redisHashUtil; @Test public void firstRedisTest() { System.out.println("***********************測試向Redis插入資料"); redisHashUtil.put("Mi8","XiaoMi",-1); redisHashUtil.put("V10","Honor",-1); redisHashUtil.put("Pro2","Smartisan",-1); redisHashUtil.put("NEX","VIVO",-1); System.out.println("**********************測試從Redis讀取資料,以及查詢資料總數"); long count = redisHashUtil.count(); List<String> all = redisHashUtil.getAll(); System.out.println("遍歷hash中的value,共計"+redisHashUtil.count()+"個品牌。分別為:"); for (String s:all) { System.out.print(s+""); } System.out.println(""); System.out.println("***********************測試Redis中是否存在指定資料"); if(redisHashUtil.isKeyExists("Pro2")){ String pro2 = redisHashUtil.get("Pro2"); System.out.println("型號為Pro2的手機存在,其品牌為:"+pro2); } System.out.println("***********************測試從Redis中刪除資料"); redisHashUtil.remove("Pro2"); if(!redisHashUtil.isKeyExists("Pro2")){ System.out.println("型號為Pro2的手機被移除了"); } System.out.print("剩餘型號還有:"); redisHashUtil.getKeys().forEach(key-> System.out.print(key+"")); System.out.println(""); System.out.println("***********************測試清空Redis中的hash資料"); redisHashUtil.clear(); System.out.println("所有手機型號都被清空,剩餘:"+redisHashUtil.count()+"個"); } }
測試結果
***********************測試向Redis插入資料 **********************測試從Redis讀取資料,以及查詢資料總數 遍歷hash中的value,共計4個品牌。分別為: XiaoMiHonorSmartisanVIVO ***********************測試Redis中是否存在指定資料 型號為Pro2的手機存在,其品牌為:Smartisan ***********************測試從Redis中刪除資料 型號為Pro2的手機被移除了 剩餘型號還有:Mi8V10NEX ***********************測試清空Redis中的hash資料 所有手機型號都被清空,剩餘:0個
看到這的老鐵都是真愛,原始碼已託管到GitHub,歡迎關注。