程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 菜鳥看Redis(一),菜鳥看redis

菜鳥看Redis(一),菜鳥看redis

編輯:JAVA綜合教程

菜鳥看Redis(一),菜鳥看redis


一、 Redis簡介

     Redis是用C語言編寫的開源軟件,可以運行在Linux上,目前不支持Windows。Redis通常會被用於緩存、數據持久化、消息隊列,Redis避免了服務器掛掉後,內存數據丟失的問題。Redis支持5種數據結構: strings, hashes, lists, sets, sorted sets,而且對於這些數據結構上的操作都是原子性的,這意味著操作這些集合是線程安全的;Redis首先是把數據集放在內存上的,可以設置每隔一段兒時間持久化數據到硬盤,如果工程中僅僅需要Redis做緩存,持久化也是可以被禁止的;Redis支持像Mysql一樣的主從同步,主服務器上的數據可以同步到N個從服務器上,可以讀寫分離。

     大多數編程語言都能使用Redis,C、C++、Java、C#、Python都能通過相應的API通過Redis服務端的IP和端口使用Redis服務。在下面的章節中主要以Java為例介紹Redis數據結構上的簡單操作。

 

二、Redis支持的數據結構以及簡單操作

1. String

  在String類數據結構上,Redis和Memcached一致,都支持Key-Value的數據存儲(一個Key對應一個Value,相當於Java中的HashMap),支持給一個Key設定一個value,支持在特定Key下的Value後添加字符串、刪除特定Key等操作、對相應Key的數字value進行原子的加減操作。

 

public class RedisClient {
    private static final String HOST="192.168.146.129";
    private static final int PORT=6379;
    
    private  final Jedis jedis=new Jedis(HOST,PORT);
    
    /**
     * 測試 Redis做Key-Value存取
     */
    @Test
    public void testKeyValue(){
        jedis.set("name", "boruoyihao");
        System.out.println("Get name from redis:"+jedis.get("name")); 
        System.out.println("Is exist in redis:"+jedis.exists("name"));
        jedis.append("name", ",Hello"); //相同Key下添加
        System.out.println("Get name from redis:"+jedis.get("name"));
        
        jedis.del("name");  //delete the Key 
        System.out.println("Get name from redis:"+jedis.get("name"));
        
        //相當於jedis.set("name","boreyihao");
        //jedis.set("age",26);
        jedis.mset("name","boreyihao","age","26");
        System.out.println(jedis.get("name")+"=="+jedis.get("age")); 
        
        //設置name有效時間為2S
        jedis.setex("name", 2, "boruo");
        System.out.println("Get name from redis:"+jedis.get("name"));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //name時間超時,取出數據為null
        System.out.println("Get name from redis:"+jedis.get("name"));
        
        //原子遞增操作
        jedis.set("age", "26");
        jedis.incr("age");
        System.out.println("Get age from redis:"+jedis.get("age"));
        jedis.decrBy("age", 3);
        System.out.println("Get age from redis:"+jedis.get("age"));
    }

}

2. hashes

     Redis的Hash可以以一個鍵值存入一個Map對象,可以獲取整個Map對象,也可以獲取Map對象的key集合或者Value集合,也可以獲取指定Field的Value,也可以對指定Field的整數值執行加減操作。Redis可以存對象的屬性以及屬性值,但是memcached存對象 只能轉化為字符串,如果要修改對象的值,只能把字符串取出來轉化為對象,然後修改對象,再轉化為字符串存回memcached,開銷還是很大的,這是Redis的優勢所在。

    @Test
    public void testHash(){
        //test hashmap
        Map<String,String>m=new HashMap<String,String>();
        m.put("name", "Tom");
        m.put("major", "Software");
        m.put("age", "43");
        jedis.hmset("m", m);
        List<String> name=jedis.hmget("m", "name"); // m為key,name為m的key,返回的是List
        System.out.println(name);
        System.out.println("Get Hash Values="+jedis.hvals("m"));
        
        Iterator<String> it=jedis.hkeys("m").iterator();
        while(it.hasNext()){
            String key=it.next();
            System.out.println(key+":"+jedis.hmget("m", key));
        }
        System.out.println("Get keys from redis:"+jedis.hkeys("m"));
        System.out.println("Get Values from redis:"+jedis.hvals("m"));
        
        Map<String,String>map=jedis.hgetAll("m");
        System.out.println("Get map from Redis:"+map);
        
        
        //Test hashset
        System.out.println("---test hash set");
        jedis.hset("s", "name", "Jack");
        jedis.hset("s", "age", "25");
        System.out.println(jedis.hexists("s", "name"));
        System.out.println(jedis.hget("s", "name"));
        System.out.println(jedis.hgetAll("s"));
        Map<String,String>smap=jedis.hgetAll("s");
        System.out.println(smap);
        
        System.out.println(jedis.hdel("s", "name"));  //清除name屬性
        System.out.println(jedis.hincrBy("s", "age", 3));
        System.out.println("after incr:"+jedis.hgetAll("s"));
    }

 

3. lists

     List是一個雙向鏈表,原因是Redis支持在這個鏈表的兩端插入和彈出操作,所以Redis的List除了是雙向鏈表外,也可以用於隊列,也可以用於棧。

    @Test
    public void testList(){
        System.out.println("test List");
        jedis.del("task");
        jedis.rpush("task", "do homework");//在鏈表尾部添加
        jedis.rpush("task", "clean housr");
        jedis.lpush("task", "rest");//在鏈表頭部添加
        jedis.lpush("task", "watch tv");
        System.out.println("length:"+jedis.llen("task"));
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1)); //-1表示到最後,表示取出從頭到尾的數據
        System.out.println("target Index:"+jedis.lindex("task", 2));
        System.out.println(jedis.lpop("task"));//取出頭部數據
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1));
        System.out.println(jedis.rpop("task"));//取出尾部數據
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1));
        
    }

 

 

 

4. sets

     Redis的Set相當於Java的hashset,元素排列有序,更強的是它可以很方便的求兩個集合的並、交、差集。

 

    @Test
    public void testSet(){
        System.out.println("test Set");
        jedis.del("s1");
        jedis.sadd("s1", "4","1","3","20");  //有序
        System.out.println("Get all s1:"+jedis.smembers("s1")); //有序的
        System.out.println("Get no s1:"+jedis.scard("s1"));
        
        jedis.sadd("s2", "4","11","13","34","3","20");
        System.out.println("Get all s2:"+jedis.smembers("s2")); //有序的
        System.out.println("Get no s2:"+jedis.scard("s2"));
        
        System.out.println(jedis.sinter("s1","s2"));//交集
        System.out.println(jedis.sunion("s1","s2")); //並集
        System.out.println(jedis.sdiff("s1","s2"));//差集
    }

 

 

 

5. sorted sets

     Redis的Sorted Sets 是對Set補充,可以根據權值進行排序,同樣不允許重復。

    @Test
    public void testSortedSet(){
        System.out.println("testSortedset");
        jedis.zadd("ss", 12, "Tom"); //中間為權值,根據權值排序
        jedis.zadd("ss", 1, "Jack");
        jedis.zadd("ss", 20, "David");
        jedis.zadd("ss", 3, "Jim");
        System.out.println("sortedset length:"+jedis.zcard("ss")); //獲取元素個數
        System.out.println("sorted set:"+jedis.zrange("ss", 0, -1));  //輸出按權值排列
        
        jedis.zadd("ss1", 1, "Tom"); //中間為權值
        jedis.zadd("ss1", 3, "Jimmy");
        jedis.zadd("ss1", 2, "Alex");
        jedis.zadd("ss1", 5, "Jim");
        
        System.out.println("sortedset length:"+jedis.zcard("ss1")); //獲取元素個數
        System.out.println("sorted set:"+jedis.zrange("ss1", 0, -1));  //輸出按權值排列
        
        System.out.println(jedis.zscore("ss1", "Tom")); //獲取Tom的排序權值
        
    }

 三、Redis應用

結合以上對Redis數據結構的介紹,Redis在服務端開發技術上,簡單來說是可以做緩存,並可以做數據持久化,以下幾方面是菜鳥的理解。

1. 消息隊列

在本文第二部分介紹了Redis有雙向鏈表List,並且支持雙進雙出,所以可以用Redis做消息隊列,比如通知的消息、任務、郵件等都可以存儲在消息隊列,然後另一端可以通過Redis能支持的大部分語言消費隊列裡的數據,這樣便於系統模塊之間的解耦,降低模塊之間的依賴性;並且把同步消息處理方式轉化為異步處理,不會造成隊列阻塞。微博的用戶微博列表應該是用Redis做的緩存。

 

2. 列出某項列表最新幾條數據

這個同樣可以用Redis中的List去處理,比如微博某大V的評論數上百萬,在頁面上顯示肯定只能顯示最新的幾十條評論,如果存在數據庫中,用Mysql的SELECT limit 查詢數據,會對所有數據進行排序,這樣的代價機會非常大,但是如果使用Redis的List就可以使用lrange(“key”,0,100)方法,這樣可以取出最近100條評論。

 

3. 計數器

因為微博有最大的Redis集群,我們還是拿微博舉例,某明星發了一個主題“我們”的微博,點贊數量兩天內幾百萬,對於這種情況,就可以使用Redis中的原子加減操作,在java中,我們知道i++或者i--並不是原子性的,也就意味著它並不是線程安全的,但是使用Redis就不會有這個問題,可以使用jedis.hincrBy("weiboid", "likes", 1);這樣表示某微博點贊數量加1,在這裡是線程安全的。

 

4. 排行榜,取TOP N數據

結合本文第二部分介紹的Sorted Set,我們可以取出TOP N的數據,比如有100W用戶參與比賽,或者100W用戶微博,我們想取出比賽成績最高的100個,或者最熱的100條微博,在這裡的比賽成績或者微博熱度都可以是權值(score),在緩存中操作,不需要進行排序,就能快速取出。

 

5. 排重與求並、差、交集

Redis使用Set,在第二部分Java程序中已經介紹,需要排重時,只需要往set集合中插入數據,Redis會自動做好去重操作,並且可以求任意兩個緩存中的set集合的並、交、差集合。

 

6. Pub/Sub

Redis支持消息發布-訂閱模式,非常適合聊天消息推送。

 

學習資料與參考文獻:

http://try.redis.io/  有Redis初學者需要學習的基本命令,提供命令行界面。

http://redis.io/topics/introduction Redis基本介紹

http://www.csdn.net/article/2013-10-07/2817107-three-giant-share-redis-experience/1  Redis在國內外應用

http://www.cnblogs.com/whoamme/p/3532129.html Redis基本操作

http://www.360doc.com/content/15/0510/20/23016082_469494498.shtml Redis應用

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved