一、相關jar包
主要用到的是jedis的核心包,筆者用到的是2.1.0版;另根據“池”的應用等還需要用到相關jar包。下圖是筆者建立的簡單的jedis測試project圖:
jar包的文檔可參考:
二、簡單的Jedis實例
在引入相關jar包後,只要new一個Jedis對象,就能做redis相關操作了。以下是一個簡單的jedis實例:
package com.pptv.redis; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import redis.clients.jedis.Jedis; public class JedisDemo { public void test(){ Jedis redis = new Jedis ("172.0.0.1",6379);//連接redis redis.auth("redis");//驗證密碼,如果需要驗證的話 // STRING 操作 //SET key value將字符串值value關聯到key。 redis.set("name", "wangjun1"); redis.set("id", "123456"); redis.set("address", "guangzhou"); //SETEX key seconds value將值value關聯到key,並將key的生存時間設爲seconds(以秒爲單位)。 redis.setex("foo", 5, "haha"); //MSET key value [key value ...]同時設置一個或多個key-value對。 redis.mset("haha","111","xixi","222"); //redis.flushAll();清空所有的key System.out.println(redis.dbSize());//dbSize是多少個key的個數 //APPEND key value如果key已經存在並且是一個字符串,APPEND命令將value追加到key原來的值之後。 redis.append("foo", "00");//如果key已經存在並且是一個字符串,APPEND命令將value追加到key原來的值之後。 //GET key 返回key所關聯的字符串值 redis.get("foo"); //MGET key [key ...] 返回所有(一個或多個)給定key的值 List list = redis.mget("haha","xixi"); for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } } public static void main(String[] args) { JedisDemo t1 = new JedisDemo(); t1.test(); } }
三、JedisPool應用
Jedis使用commons-pool完成池化實現。
先做個配置文件(properties文件):
#最大分配的對象數 redis.pool.maxActive=1024 #最大能夠保持idel狀態的對象數 redis.pool.maxIdle=200 #當池內沒有返回對象時,最大等待時間 redis.pool.maxWait=1000 #當調用borrow Object方法時,是否進行有效性檢查 redis.pool.testOnBorrow=true #當調用return Object方法時,是否進行有效性檢查 redis.pool.testOnReturn=true #IP redis.ip=172.0.0.1 #Port redis.port=6379
jedisPool的相關詳細配置可參考:http://www.2cto.com/database/201311/254449.html
在靜態代碼段中完成初始化:
private static JedisPool pool; static { ResourceBundle bundle = ResourceBundle.getBundle("redis"); if (bundle == null) { throw new IllegalArgumentException( "[redis.properties] is not found!"); } JedisPoolConfig config = new JedisPoolConfig(); config.setMaxActive(Integer.valueOf(bundle .getString("redis.pool.maxActive"))); config.setMaxIdle(Integer.valueOf(bundle .getString("redis.pool.maxIdle"))); config.setMaxWait(Long.valueOf(bundle.getString("redis.pool.maxWait"))); config.setTestOnBorrow(Boolean.valueOf(bundle .getString("redis.pool.testOnBorrow"))); config.setTestOnReturn(Boolean.valueOf(bundle .getString("redis.pool.testOnReturn"))); pool = new JedisPool(config, bundle.getString("redis.ip"), Integer.valueOf(bundle.getString("redis.port"))); }
然後修改#2的簡單實例,修改爲Jedis從pool中獲得:
// 從池中獲取一個Jedis對象 Jedis jedis = pool.getResource(); String keys = "name"; // 刪數據 jedis.del(keys); // 存數據 jedis.set(keys, "snowolf"); // 取數據 String value = jedis.get(keys); System.out.println(value); // 釋放對象池 pool.returnResource(jedis);
四、Jedis分佈式(Sharding/shared一致性哈希)
Memcached完全基於分佈式集羣,而Redis是Master-Slave,如果想把Reids,做成集羣模式,無外乎多做幾套Master-Slave,每套Master-Slave完成各自的容災處理,通過Client工具,完成一致性哈希。(PS:Memcached是在Server端完成Sharding,Redis只能依靠各個Client做Sharding。可能會在Redis 3.0系列支持Server端Sharding。)
shared一致性哈希採用以下方案:
Redis服務器節點劃分:將每臺服務器節點採用hash算法劃分爲160個虛擬節點(可以配置劃分權重)
將劃分虛擬節點採用TreeMap存儲
對每個Redis服務器的物理連接採用LinkedHashMap存儲
對Key or KeyTag 採用同樣的hash算法,然後從TreeMap獲取大於等於鍵hash值得節點,取最鄰近節點存儲;當key的hash值大於虛擬節點hash值得最大值時,存入第一個虛擬節點
sharded採用的hash算法:MD5 和 MurmurHash兩種;默認採用64位的MurmurHash算法;有興趣的可以研究下,MurmurHash是一種高效,低碰撞的hash算法;參考地址:
保留前面的JedisPoolConfig,新增兩個Redis的IP(redis1.ip,redis2.ip),完成兩個JedisShardInfo實例,並將其丟進List中:
JedisShardInfo jedisShardInfo1 = new JedisShardInfo( bundle.getString("redis1.ip"), Integer.valueOf(bundle .getString("redis.port"))); JedisShardInfo jedisShardInfo2 = new JedisShardInfo( bundle.getString("redis2.ip"), Integer.valueOf(bundle .getString("redis.port"))); List<JedisShardInfo> list = new LinkedList<JedisShardInfo>(); list.add(jedisShardInfo1); list.add(jedisShardInfo2);
初始化ShardedJedisPool代替JedisPool:
ShardedJedisPool pool = new ShardedJedisPool(config, list);
改由ShardedJedis,獲取Jedis對象:
// 從池中獲取一個Jedis對象 ShardedJedis jedis = pool.getResource(); String keys = "name"; String value = "snowolf"; // 刪數據 jedis.del(keys); // 存數據 jedis.set(keys, value); // 取數據 String v = jedis.get(keys); System.out.println(v); // 釋放對象池 pool.returnResource(jedis);
通過以上方式,向redis進行set操作的key-value,會通過hash而均勻的分配到pool裏的redis機器中。
五、綜合實例
package com.pptv.redis; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; /** * redis的Java客戶端Jedis測試驗證 * * @author */ public class Test { /** * 非切片客戶端鏈接 */ private Jedis jedis; /** * 非切片鏈接池 */ private JedisPool jedisPool; /** * 切片客戶端鏈接 */ private ShardedJedis shardedJedis; /** * 切片鏈接池 */ private ShardedJedisPool shardedJedisPool; private String ip = "172.16.205.186"; /** * 構造函數 */ public Test() { initialPool(); initialShardedPool(); shardedJedis = shardedJedisPool.getResource(); jedis = jedisPool.getResource(); } private void initialPool() { // 池基本配置 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxActive(20); config.setMaxIdle(5); config.setMaxWait(1000l); config.setTestOnBorrow(false); jedisPool = new JedisPool(config, ip, 6379); } /** * 初始化切片池 */ private void initialShardedPool() { // 池基本配置 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxActive(20); config.setMaxIdle(5); config.setMaxWait(1000l); config.setTestOnBorrow(false); // slave鏈接 List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>(); shards.add(new JedisShardInfo(ip, 6379, "master")); // 構造池 shardedJedisPool = new ShardedJedisPool(config, shards); } public void show() { // key檢測 testKey(); // string檢測 testString(); // list檢測 testList(); // set檢測 testSet(); // sortedSet檢測 testSortedSet(); // hash檢測 testHash(); shardedJedisPool.returnResource(shardedJedis); } private void testKey() { System.out.println("=============key=========================="); // 清空數據 System.out.println(jedis.flushDB()); System.out.println(jedis.echo("foo")); // 判斷key否存在 System.out.println(shardedJedis.exists("foo")); shardedJedis.set("key", "values"); System.out.println(shardedJedis.exists("key")); } private void testString() { System.out.println("=============String=========================="); // 清空數據 System.out.println(jedis.flushDB()); // 存儲數據 shardedJedis.set("foo", "bar"); System.out.println(shardedJedis.get("foo")); // 若key不存在,則存儲 shardedJedis.setnx("foo", "foo not exits"); System.out.println(shardedJedis.get("foo")); // 覆蓋數據 shardedJedis.set("foo", "foo update"); System.out.println(shardedJedis.get("foo")); // 追加數據 shardedJedis.append("foo", " hello, world"); System.out.println(shardedJedis.get("foo")); // 設置key的有效期,並存儲數據 shardedJedis.setex("foo", 2, "foo not exits"); System.out.println(shardedJedis.get("foo")); try { Thread.sleep(3000); } catch (InterruptedException e) { } System.out.println(shardedJedis.get("foo")); // 獲取並更改數據 shardedJedis.set("foo", "foo update"); System.out.println(shardedJedis.getSet("foo", "foo modify")); // 截取value的值 System.out.println(shardedJedis.getrange("foo", 1, 3)); System.out.println(jedis.mset("mset1", "mvalue1", "mset2", "mvalue2", "mset3", "mvalue3", "mset4", "mvalue4")); System.out.println(jedis.mget("mset1", "mset2", "mset3", "mset4")); System.out.println(jedis.del(new String[] { "foo", "foo1", "foo3" })); } private void testList() { System.out.println("=============list=========================="); // 清空數據 System.out.println(jedis.flushDB()); // 添加數據 shardedJedis.lpush("lists", "vector"); shardedJedis.lpush("lists", "ArrayList"); shardedJedis.lpush("lists", "LinkedList"); // 數組長度 System.out.println(shardedJedis.llen("lists")); // 排序 // System.out.println(shardedJedis.sort("lists")); // 字串 System.out.println(shardedJedis.lrange("lists", 0, 3)); // 修改列表中單個值 shardedJedis.lset("lists", 0, "hello list!"); // 獲取列表指定下標的值 System.out.println(shardedJedis.lindex("lists", 1)); // 刪除列表指定下標的值 System.out.println(shardedJedis.lrem("lists", 1, "vector")); // 刪除區間以外的數據 System.out.println(shardedJedis.ltrim("lists", 0, 1)); // 列表出棧 System.out.println(shardedJedis.lpop("lists")); // 整個列表值 System.out.println(shardedJedis.lrange("lists", 0, -1)); } private void testSet() { System.out.println("=============set=========================="); // 清空數據 System.out.println(jedis.flushDB()); // 添加數據 shardedJedis.sadd("sets", "HashSet"); shardedJedis.sadd("sets", "SortedSet"); shardedJedis.sadd("sets", "TreeSet"); // 判斷value是否在列表中 System.out.println(shardedJedis.sismember("sets", "TreeSet")); ; // 整個列表值 System.out.println(shardedJedis.smembers("sets")); // 刪除指定元素 System.out.println(shardedJedis.srem("sets", "SortedSet")); // 出棧 System.out.println(shardedJedis.spop("sets")); System.out.println(shardedJedis.smembers("sets")); // shardedJedis.sadd("sets1", "HashSet1"); shardedJedis.sadd("sets1", "SortedSet1"); shardedJedis.sadd("sets1", "TreeSet"); shardedJedis.sadd("sets2", "HashSet2"); shardedJedis.sadd("sets2", "SortedSet1"); shardedJedis.sadd("sets2", "TreeSet1"); // 交集 System.out.println(jedis.sinter("sets1", "sets2")); // 並集 System.out.println(jedis.sunion("sets1", "sets2")); // 差集 System.out.println(jedis.sdiff("sets1", "sets2")); } private void testSortedSet() { System.out.println("=============zset=========================="); // 清空數據 System.out.println(jedis.flushDB()); // 添加數據 shardedJedis.zadd("zset", 10.1, "hello"); shardedJedis.zadd("zset", 10.0, ":"); shardedJedis.zadd("zset", 9.0, "zset"); shardedJedis.zadd("zset", 11.0, "zset!"); // 元素個數 System.out.println(shardedJedis.zcard("zset")); // 元素下標 System.out.println(shardedJedis.zscore("zset", "zset")); // 集合子集 System.out.println(shardedJedis.zrange("zset", 0, -1)); // 刪除元素 System.out.println(shardedJedis.zrem("zset", "zset!")); System.out.println(shardedJedis.zcount("zset", 9.5, 10.5)); // 整個集合值 System.out.println(shardedJedis.zrange("zset", 0, -1)); } private void testHash() { System.out.println("=============hash=========================="); // 清空數據 System.out.println(jedis.flushDB()); // 添加數據 shardedJedis.hset("hashs", "entryKey", "entryValue"); shardedJedis.hset("hashs", "entryKey1", "entryValue1"); shardedJedis.hset("hashs", "entryKey2", "entryValue2"); // 判斷某個值是否存在 System.out.println(shardedJedis.hexists("hashs", "entryKey")); // 獲取指定的值 System.out.println(shardedJedis.hget("hashs", "entryKey")); // 批量獲取指定的值 System.out .println(shardedJedis.hmget("hashs", "entryKey", "entryKey1")); // 刪除指定的值 System.out.println(shardedJedis.hdel("hashs", "entryKey")); // 爲key中的域 field 的值加上增量 increment System.out.println(shardedJedis.hincrBy("hashs", "entryKey", 123l)); // 獲取所有的keys System.out.println(shardedJedis.hkeys("hashs")); // 獲取所有的values System.out.println(shardedJedis.hvals("hashs")); } /** * @param args */ public static void main(String[] args) { new Test().show(); } }