關注公衆號:CoderBuff,回覆「redis」獲取《Redis5.x入門教程》完整版PDF。html
有關本章的源碼:https://github.com/yu-linfeng/redis5.x_tutorial/tree/master/code/jedisjava
前面的章節介紹了redis的安裝、還有命令配置等內容,咱們在實際使用時大部分狀況都是利用現成的Java客戶端對redis進行操做。固然命令並非沒用,它極有可能在你排查問題時排上用場,由於你有可能會直接連入redis服務端經過命令行來排查是不是redis緩存的問題。git
redis的Java客戶端最經常使用的是jedis開源庫,本章咱們也將圍繞jedis的對redis進行一些簡單的操做,jedis的GitHub地址:https://github.com/xetorthio/jedis。程序員
package com.coderbuff.jedis.simple; import redis.clients.jedis.Jedis; /** * @author okevin * @date 2020/2/12 23:08 */ public class Demo { public static void main(String[] args) { Jedis jedis = new Jedis("localhost"); jedis.set("redis-client", "jedis"); System.out.println(jedis.get("redis-client")); jedis.close(); } }
這是一個簡單的jedis鏈接示例,使用MySQL的經驗告訴咱們:相似有socket鏈接的,咱們最好是經過「池化」技術,一是更好的管理咱們的鏈接;二是能更好的利用鏈接資源。因此當咱們在使用jedis時,最好是使用jedis提供的池化技術。github
package com.codrbuff.jedis.client; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * redis客戶端鏈接 * @author okevin * @date 2020/2/12 23:17 */ public class RedisClient { /** * redis服務器地址 */ private static final String HOST = "localhost"; /** * jedis鏈接池 */ private static JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), HOST); private RedisClient() { } /** * 從jedispool中獲取一個jedis鏈接 * @return jedis鏈接 */ public static Jedis getJedis() { return jedisPool.getResource(); } }
package com.coderbuff.jedis.util; import com.codrbuff.jedis.client.RedisClient; import redis.clients.jedis.Jedis; /** * redis工具類 * @author okevin * @date 2020/2/12 23:13 */ public class RedisUtil { //###########字符串(string)數據類型相關操做############ /** * 字符串寫入 * @param key key * @param value 值 * @return 寫入的值 */ public static String set(String key, String value) { try (Jedis jedis = RedisClient.getJedis()){ jedis.set(key, value); return value; } } public static String get(String key) { try (Jedis jedis = RedisClient.getJedis()) { return jedis.get(key); } } }
固然我不許備在這裏把全部的命令都展現出來,關於SDK的使用大可查看官方文檔。redis
redis中有一個重要的功能——pipeline(管道),咱們在操做大量數據時,redis的吞吐量性能可能較低,此時咱們能夠經過pipeline進行批量操做。這個功能在redis的命令中並無,但redis是支持的。因此本章將重點介紹pipeline的使用,這在實際應用中很是經常使用。緩存
pipeline提供了命令的批量提交,當咱們有批量查詢或者寫入操做時,單個命令的「往返時間」是1ms,那麼10個命令就會消耗10ms,若是咱們使用pipeline批量操做後能夠一次性提交10個命令,redis的響應時間將會大大減少。吞吐量也天然提升。服務器
實際上,之因此採用pipeline批量提交主要是爲了控制網絡開銷,10個命令就會有10次網絡開銷,網絡開銷對於處於異地機房的影響尤其明顯。因此在進行批量操做時,儘可能使用pipeline管道操做。下面的例子是1萬次字符串類型的寫入,反映了非pipeline和pipeline的性能對比。網絡
package com.coderbff.jedis.test; import com.coderbuff.jedis.util.RedisUtil; import com.codrbuff.jedis.client.RedisClient; import org.junit.Test; import redis.clients.jedis.Pipeline; /** * @author okevin * @date 2020/2/12 23:32 */ public class JedisTests { @Test public void testPipeline() { long setStart = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { RedisUtil.set("key_" + i, String.valueOf(i)); } long setEnd = System.currentTimeMillis(); System.out.println("非pipeline操做10000次字符串數據類型set寫入,耗時:" + (setEnd - setStart) + "毫秒"); long pipelineStart = System.currentTimeMillis(); Pipeline pipeline = RedisClient.getJedis().pipelined(); for (int i = 0; i < 10000; i++) { pipeline.set("key_" + i, String.valueOf(i)); } pipeline.sync(); long pipelineEnd = System.currentTimeMillis(); System.out.println("pipeline操做10000次字符串數據類型set寫入,耗時:" + (pipelineEnd - pipelineStart) + "毫秒"); } }
控制檯輸出結果:socket
非pipeline操做10000次字符串數據類型set寫入,耗時:1843毫秒 pipeline操做10000次字符串數據類型set寫入,耗時:205毫秒
能夠看到,經過pipeline管道批量操做,吞吐量性能大大提到。
重要
使用pipeline有幾個值得注意的地方:
mset
是原子性的。mset
批量操做要麼都成功要麼都失敗,而pipeline則不能保證。mset
只是set
一個命令的批量操做,而pipeline則能夠批量發送多個命令,這裏就存在事務的問題。針對問題一,咱們在進行批量操做時應儘量的把批量操做拆分紅小粒度的pipeline。
針對問題二,要保證多個命令的事務,就須要使用redis提供的事務相關的命令,但redis中的事務是「假事務」,由於它仍然不能保證原子性。在下一章中,會詳細介紹redis原生的簡單事務(不保證原子性),以及如何在redis中保證事務的原子性。
關注公衆號:CoderBuff,回覆「redis」獲取《Redis5.x入門教程》完整版PDF。