Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式)介绍
- 一、普通同步方式
- 二、事務方式(Transactions)
- 三、管道(Pipelining)
- 四、管道中調用事務
- 五、分布式直連同步調用
- 六、分布式直連異步調用
- 七、分布式連接池同步調用
- 八、分布式連接池異步調用
- 九、需要注意的地方
- 十、測試
- 十一、完整的測試代碼
jedis是一個著名的key-value存儲系統,而作為其官方推薦的java版客戶端jedis也非常強大和穩定,支持事務、管道及有jedis自身實現的分布式。
在這里對jedis關于事務、管道和分布式的調用方式做一個簡單的介紹和對比:
一、普通同步方式
最簡單和基礎的調用方式,
?| 1 2 3 4 5 6 7 8 9 10 11 | @Test public?void?test1Normal()?{ ????Jedis?jedis?=?new?Jedis("localhost"); ????long?start?=?System.currentTimeMillis(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????String?result?=?jedis.set("n"?+?i,?"n"?+?i); ????} ????long?end?=?System.currentTimeMillis(); ????System.out.println("Simple?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????jedis.disconnect(); } |
很簡單吧,每次set之后都可以返回結果,標記是否成功。
二、事務方式(Transactions)
redis的事務很簡單,他主要目的是保障,一個client發起的事務中的命令可以連續的執行,而中間不會插入其他client的命令。
看下面例子:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 | @Test public?void?test2Trans()?{ ????Jedis?jedis?=?new?Jedis("localhost"); ????long?start?=?System.currentTimeMillis(); ????Transaction?tx?=?jedis.multi(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????tx.set("t"?+?i,?"t"?+?i); ????} ????List<Object>?results?=?tx.exec(); ????long?end?=?System.currentTimeMillis(); ????System.out.println("Transaction?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????jedis.disconnect(); } |
我們調用jedis.watch(…)方法來監控key,如果調用后key值發生變化,則整個事務會執行失敗。另外,事務中某個操作失敗,并不會回滾其他操作。這一點需要注意。還有,我們可以使用discard()方法來取消事務。
三、管道(Pipelining)
有時,我們需要采用異步方式,一次發送多個指令,不同步等待其返回結果。這樣可以取得非常好的執行效率。這就是管道,調用方法如下:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 | @Test public?void?test3Pipelined()?{ ????Jedis?jedis?=?new?Jedis("localhost"); ????Pipeline?pipeline?=?jedis.pipelined(); ????long?start?=?System.currentTimeMillis(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????pipeline.set("p"?+?i,?"p"?+?i); ????} ????List<Object>?results?=?pipeline.syncAndReturnAll(); ????long?end?=?System.currentTimeMillis(); ????System.out.println("Pipelined?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????jedis.disconnect(); } |
四、管道中調用事務
就Jedis提供的方法而言,是可以做到在管道中使用事務,其代碼如下:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Test public?void?test4combPipelineTrans()?{ ????jedis?=?new?Jedis("localhost");? ????long?start?=?System.currentTimeMillis(); ????Pipeline?pipeline?=?jedis.pipelined(); ????pipeline.multi(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????pipeline.set(""?+?i,?""?+?i); ????} ????pipeline.exec(); ????List<Object>?results?=?pipeline.syncAndReturnAll(); ????long?end?=?System.currentTimeMillis(); ????System.out.println("Pipelined?transaction:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????jedis.disconnect(); } |
但是經測試(見本文后續部分),發現其效率和單獨使用事務差不多,甚至還略微差點。
五、分布式直連同步調用
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Test public?void?test5shardNormal()?{ ????List<JedisShardInfo>?shards?=?Arrays.asList( ????????????new?JedisShardInfo("localhost",6379), ????????????new?JedisShardInfo("localhost",6380)); ????ShardedJedis?sharding?=?new?ShardedJedis(shards); ????long?start?=?System.currentTimeMillis(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????String?result?=?sharding.set("sn"?+?i,?"n"?+?i); ????} ????long?end?=?System.currentTimeMillis(); ????System.out.println("Simple@Sharing?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????sharding.disconnect(); } |
這個是分布式直接連接,并且是同步調用,每步執行都返回執行結果。類似地,還有異步管道調用。
六、分布式直連異步調用
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @Test public?void?test6shardpipelined()?{ ????List<JedisShardInfo>?shards?=?Arrays.asList( ????????????new?JedisShardInfo("localhost",6379), ????????????new?JedisShardInfo("localhost",6380)); ????ShardedJedis?sharding?=?new?ShardedJedis(shards); ????ShardedJedisPipeline?pipeline?=?sharding.pipelined(); ????long?start?=?System.currentTimeMillis(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????pipeline.set("sp"?+?i,?"p"?+?i); ????} ????List<Object>?results?=?pipeline.syncAndReturnAll(); ????long?end?=?System.currentTimeMillis(); ????System.out.println("Pipelined@Sharing?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????sharding.disconnect(); } |
七、分布式連接池同步調用
如果,你的分布式調用代碼是運行在線程中,那么上面兩個直連調用方式就不合適了,因為直連方式是非線程安全的,這個時候,你就必須選擇連接池調用。
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @Test public?void?test7shardSimplePool()?{ ????List<JedisShardInfo>?shards?=?Arrays.asList( ????????????new?JedisShardInfo("localhost",6379), ????????????new?JedisShardInfo("localhost",6380)); ????ShardedJedisPool?pool?=?new?ShardedJedisPool(new?JedisPoolConfig(),?shards); ????ShardedJedis?one?=?pool.getResource(); ????long?start?=?System.currentTimeMillis(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????String?result?=?one.set("spn"?+?i,?"n"?+?i); ????} ????long?end?=?System.currentTimeMillis(); ????pool.returnResource(one); ????System.out.println("Simple@Pool?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????pool.destroy(); } |
上面是同步方式,當然還有異步方式。
八、分布式連接池異步調用
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Test public?void?test8shardPipelinedPool()?{ ????List<JedisShardInfo>?shards?=?Arrays.asList( ????????????new?JedisShardInfo("localhost",6379), ????????????new?JedisShardInfo("localhost",6380)); ????ShardedJedisPool?pool?=?new?ShardedJedisPool(new?JedisPoolConfig(),?shards); ????ShardedJedis?one?=?pool.getResource(); ????ShardedJedisPipeline?pipeline?=?one.pipelined(); ????long?start?=?System.currentTimeMillis(); ????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????pipeline.set("sppn"?+?i,?"n"?+?i); ????} ????List<Object>?results?=?pipeline.syncAndReturnAll(); ????long?end?=?System.currentTimeMillis(); ????pool.returnResource(one); ????System.out.println("Pipelined@Pool?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????pool.destroy(); } |
九、需要注意的地方
事務和管道都是異步模式。在事務和管道中不能同步查詢結果。比如下面兩個調用,都是不允許的:
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | ?Transaction?tx?=?jedis.multi(); ?for?(int?i?=?0;?i?<?100000;?i++)?{ ?????tx.set("t"?+?i,?"t"?+?i); ?} ?System.out.println(tx.get("t1000").get());??//不允許 ?List<Object>?results?=?tx.exec(); ?… ?… ?Pipeline?pipeline?=?jedis.pipelined(); ?long?start?=?System.currentTimeMillis(); ?for?(int?i?=?0;?i?<?100000;?i++)?{ ?????pipeline.set("p"?+?i,?"p"?+?i); ?} ?System.out.println(pipeline.get("p1000").get());?//不允許 ?List<Object>?results?=?pipeline.syncAndReturnAll(); |
事務和管道都是異步的,個人感覺,在管道中再進行事務調用,沒有必要,不如直接進行事務模式。
分布式中,連接池的性能比直連的性能略好(見后續測試部分)。
分布式調用中不支持事務。
因為事務是在服務器端實現,而在分布式中,每批次的調用對象都可能訪問不同的機器,所以,沒法進行事務。
十、測試
運行上面的代碼,進行測試,其結果如下:
?| 1 2 3 4 5 6 7 8 9 10 11 | Simple?SET:?5.227?seconds Transaction?SET:?0.5?seconds Pipelined?SET:?0.353?seconds Pipelined?transaction:?0.509?seconds Simple@Sharing?SET:?5.289?seconds Pipelined@Sharing?SET:?0.348?seconds Simple@Pool?SET:?5.039?seconds Pipelined@Pool?SET:?0.401?seconds |
另外,經測試分布式中用到的機器越多,調用會越慢。上面是2片,下面是5片:
?| 1 2 3 4 | Simple@Sharing?SET:?5.494?seconds Pipelined@Sharing?SET:?0.51?seconds Simple@Pool?SET:?5.223?seconds Pipelined@Pool?SET:?0.518?seconds |
下面是10片:
?| 1 2 3 4 | Simple@Sharing?SET:?5.9?seconds Pipelined@Sharing?SET:?0.794?seconds Simple@Pool?SET:?5.624?seconds Pipelined@Pool?SET:?0.762?seconds |
下面是100片:
?| 1 2 3 4 | Simple@Sharing?SET:?14.055?seconds Pipelined@Sharing?SET:?8.185?seconds Simple@Pool?SET:?13.29?seconds Pipelined@Pool?SET:?7.767?seconds |
分布式中,連接池方式調用不但線程安全外,根據上面的測試數據,也可以看出連接池比直連的效率更好。
十一、完整的測試代碼
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | package?com.example.nosqlclient; import?java.util.Arrays; import?java.util.List; import?org.junit.AfterClass; import?org.junit.BeforeClass; import?org.junit.Test; import?redis.clients.jedis.Jedis; import?redis.clients.jedis.JedisPoolConfig; import?redis.clients.jedis.JedisShardInfo; import?redis.clients.jedis.Pipeline; import?redis.clients.jedis.ShardedJedis; import?redis.clients.jedis.ShardedJedisPipeline; import?redis.clients.jedis.ShardedJedisPool; import?redis.clients.jedis.Transaction; import?org.junit.FixMethodOrder; import?org.junit.runners.MethodSorters; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public?class?TestJedis?{ ????private?static?Jedis?jedis; ????private?static?ShardedJedis?sharding; ????private?static?ShardedJedisPool?pool; ????@BeforeClass ????public?static?void?setUpBeforeClass()?throws?Exception?{ ????????List<JedisShardInfo>?shards?=?Arrays.asList( ????????????????new?JedisShardInfo("localhost",6379), ????????????????new?JedisShardInfo("localhost",6379));?//使用相同的ip:port,僅作測試 ????????jedis?=?new?Jedis("localhost");? ????????sharding?=?new?ShardedJedis(shards); ????????pool?=?new?ShardedJedisPool(new?JedisPoolConfig(),?shards); ????} ????@AfterClass ????public?static?void?tearDownAfterClass()?throws?Exception?{ ????????jedis.disconnect(); ????????sharding.disconnect(); ????????pool.destroy(); ????} ????@Test ????public?void?test1Normal()?{ ????????long?start?=?System.currentTimeMillis(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????String?result?=?jedis.set("n"?+?i,?"n"?+?i); ????????} ????????long?end?=?System.currentTimeMillis(); ????????System.out.println("Simple?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} ????@Test ????public?void?test2Trans()?{ ????????long?start?=?System.currentTimeMillis(); ????????Transaction?tx?=?jedis.multi(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????tx.set("t"?+?i,?"t"?+?i); ????????} ????????//System.out.println(tx.get("t1000").get()); ????????List<Object>?results?=?tx.exec(); ????????long?end?=?System.currentTimeMillis(); ????????System.out.println("Transaction?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} ????@Test ????public?void?test3Pipelined()?{ ????????Pipeline?pipeline?=?jedis.pipelined(); ????????long?start?=?System.currentTimeMillis(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????pipeline.set("p"?+?i,?"p"?+?i); ????????} ????????//System.out.println(pipeline.get("p1000").get()); ????????List<Object>?results?=?pipeline.syncAndReturnAll(); ????????long?end?=?System.currentTimeMillis(); ????????System.out.println("Pipelined?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} ????@Test ????public?void?test4combPipelineTrans()?{ ????????long?start?=?System.currentTimeMillis(); ????????Pipeline?pipeline?=?jedis.pipelined(); ????????pipeline.multi(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????pipeline.set(""?+?i,?""?+?i); ????????} ????????pipeline.exec(); ????????List<Object>?results?=?pipeline.syncAndReturnAll(); ????????long?end?=?System.currentTimeMillis(); ????????System.out.println("Pipelined?transaction:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} ????@Test ????public?void?test5shardNormal()?{ ????????long?start?=?System.currentTimeMillis(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????String?result?=?sharding.set("sn"?+?i,?"n"?+?i); ????????} ????????long?end?=?System.currentTimeMillis(); ????????System.out.println("Simple@Sharing?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} ????@Test ????public?void?test6shardpipelined()?{ ????????ShardedJedisPipeline?pipeline?=?sharding.pipelined(); ????????long?start?=?System.currentTimeMillis(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????pipeline.set("sp"?+?i,?"p"?+?i); ????????} ????????List<Object>?results?=?pipeline.syncAndReturnAll(); ????????long?end?=?System.currentTimeMillis(); ????????System.out.println("Pipelined@Sharing?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} ????@Test ????public?void?test7shardSimplePool()?{ ????????ShardedJedis?one?=?pool.getResource(); ????????long?start?=?System.currentTimeMillis(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????String?result?=?one.set("spn"?+?i,?"n"?+?i); ????????} ????????long?end?=?System.currentTimeMillis(); ????????pool.returnResource(one); ????????System.out.println("Simple@Pool?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} ????@Test ????public?void?test8shardPipelinedPool()?{ ????????ShardedJedis?one?=?pool.getResource(); ????????ShardedJedisPipeline?pipeline?=?one.pipelined(); ????????long?start?=?System.currentTimeMillis(); ????????for?(int?i?=?0;?i?<?100000;?i++)?{ ????????????pipeline.set("sppn"?+?i,?"n"?+?i); ????????} ????????List<Object>?results?=?pipeline.syncAndReturnAll(); ????????long?end?=?System.currentTimeMillis(); ????????pool.returnResource(one); ????????System.out.println("Pipelined@Pool?SET:?"?+?((end?-?start)/1000.0)?+?"?seconds"); ????} } |
參考:http://www.open-open.com/lib/view/open1410485827242.html
轉載于:https://www.cnblogs.com/songjinduo/p/5151139.html
總結
以上是生活随笔為你收集整理的Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式)介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全国计算机等级考试题库二级C操作题100
- 下一篇: JavaWeb 如何防止表单重复提交 -