1. 程式人生 > >Redis 程式設計(Idea 安裝加配置)

Redis 程式設計(Idea 安裝加配置)

Redis 的特點

  1. 速度快,執行在記憶體中,執行速度非常快。
  2. 資料型別豐富:
    1. String,上限512MB
    2. List
    3. set
    4. sorted set,每個元素關聯一個 score,以提供排序依據
    5. hash,字串與字串之間的對映
  3. 操作原子性,所有的 Redis 操作都是原子的,保證多個客戶端併發訪問時獲取到 Redis 伺服器的值為最新值。
  4. 持久化,與 Memcache 不同的是,Redis 提供了資料持久化的功能,提供 AOF 和 RDB 兩種持久化模式。
    1. AOF,只追加資料到檔案,記錄所有的寫指令。
    2. RDB,先將資料寫到臨時檔案,再用臨時檔案替換上次持久化好的檔案,會單獨 fork 一個程序進行持久化,而主程序不進行任何 IO 操作。
  5. 應用場景豐富:快取、訊息、佇列(Redis 原生支援訂閱/釋出)、資料庫等。

Pub/Sub功能(means Publish, Subscribe)即釋出及訂閱功能。基於事件的系統中,Pub/Sub是目前廣泛使用的通訊模型,它採用事件作為基本的通訊機制,提供大規模系統所要求的鬆散耦合的互動模式:訂閱者(如客戶端)以事件訂閱的方式表達出它有興趣接收的一個事件或一類事件;釋出者(如伺服器)可將訂閱者感興趣的事件隨時通知相關訂閱者。

Redis 的主從複製

Redis 的主從同步是非同步執行的,因此主從同步並不會減少 Redis 的執行效能。給 Redis 主伺服器新增一個伺服器,只需要在從伺服器的 redis.conf 中新增 slaveof masterip masterpot 命令,先啟動主伺服器,再啟動從伺服器,從伺服器會根據配置中的主伺服器的 IP 埠對主伺服器發出同步命令,然後進行資料同步。

多組主從同步及主從切換可以通過 Redis Sentinel 進行管理,Sentinel 能對 Redis 叢集中的主伺服器及從伺服器進行管理,當主節點宕機時,Sentinel 能自動切換到從伺服器。

Redis 安裝配置

Redis 示例

Redis 工具類封裝

import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Tuple;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * Mac
 * 下載:https://redis.io/download
 * 解壓:tar zxvf redis-5.0.2.tar.gz
 * 移動到: mv redis-5.0.2 /usr/local/
 * 切換到:cd /usr/local/redis-5.0.2/
 * 編譯測試 sudo make test
 * 編譯安裝 sudo make install
 * 啟動:redis-server
 * <p>
 * For idea:Iedis
 * <p>
 * Redis 命令參考:http://redisdoc.com/index.html
 */
public class Redis {
    private static Redis instance;
    public static Logger log = LoggerFactory.getLogger(Redis.class);
    public static final int DB = 0;// 預設資料庫

    public static Redis getInstance() {
        if (instance == null) {
            instance = new Redis();
            instance.init();
        }
        return instance;
    }

    private JedisPool pool;
    public String host;
    public int port;

    private void init() {
        host = "127.0.0.1";
        port = 6379;
        log.info("Redis at {}:{}", host, port);
        pool = new JedisPool(host, port);
    }

    public static void destroy() {
        getInstance().pool.destroy();
    }

    //    hash 與 object 之間的相互轉換
    public static Map<String, String> objectToHash(Object obj)
            throws IntrospectionException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        Map<String, String> map = new HashMap<>();
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor property : propertyDescriptors) {
            if (!property.getName().equals("class")) {
                map.put(property.getName(), ""
                        + property.getReadMethod().invoke(obj));
            }
        }
        return map;
    }

    public static void hashToObject(Map<?, ?> map, Object obj)
            throws IllegalAccessException, InvocationTargetException {
        for (Map.Entry<?, ?> entry : map.entrySet()) {
            if (entry.getValue().equals("null")) {
                entry.setValue(null);
            }
        }
        BeanUtils.populate(obj, map);
    }

    @SuppressWarnings("unchecked")
    public static <T> T hashToObject(Map<?, ?> map, Class c)
            throws IllegalAccessException, InvocationTargetException,
            InstantiationException {
        Object obj;
        try {
            obj = c.getDeclaredConstructor().newInstance();
            hashToObject(map, obj);
            return (T) obj;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    //    Redis 雜湊操作:hmget,hmset,hexist,hdel,hgetAll,hget,hset
    public List<String> hmget(int db, String key, String... fields) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        List<String> ret = redis.hmget(key, fields);
        redis.select(db);
        redis.close();
        return ret;
    }

    public String hmset(int db, String key, Object object)
            throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, IntrospectionException {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        String ret = redis.hmset(key, objectToHash(object));
        redis.close();
        return ret;
    }

    public String hmset(int db, String key, Map<String, String> fields)
            throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException, IntrospectionException {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        String ret = redis.hmset(key, fields);
        redis.close();
        return ret;
    }

    public boolean hexist(int db, String key, String field) {
        if (key == null) {
            return false;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        boolean ret = redis.hexists(key, field);
        redis.close();
        return ret;
    }

    public Long hdel(int db, String key, String... fields) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Long cnt = redis.hdel(key, fields);
        redis.close();
        return cnt;
    }

    public Map<String, String> hgetAll(int db, String key) {
        if (key == null) {
            return null;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Map<String, String> ret = redis.hgetAll(key);
        redis.close();
        return ret;
    }

    public String hget(int db, String key, String field) {
        if (key == null) {
            return null;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        String ret = redis.hget(key, field);
        redis.close();
        return ret;
    }

    public void hset(int db, String key, String field, String value) {
        if (field == null || field.length() == 0) {
            return;
        }
        if (value == null || value.length() == 0) {
            return;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        redis.hset(key, field, value);
        redis.close();
    }

    //    Redis 字串操作:set,get
    public void set(int db, String key, String value) {
        if (value == null || key == null) {
            return;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        redis.set(key, value);
        redis.close();
    }

    public String get(int db, String key) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        String ret = redis.get(key);
        redis.close();
        return ret;
    }

    //    Redis 集合操作:sadd,smove,sremove,sget,scard,sismember

    /**
     * 新增元素到集合中
     *
     * @param key
     * @param element
     */
    public boolean sadd(int db, String key, String... element) {
        if (element == null || element.length == 0) {
            return false;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        boolean success = redis.sadd(key, element) == 1;
        redis.close();
        return success;
    }

    public boolean smove(int db, String oldKey, String newKey, String element) {
        if (element == null) {
            return false;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        boolean success = (redis.smove(oldKey, newKey, element) == 1);
        redis.close();
        return success;
    }

    /**
     * 刪除指定set內的元素
     */
    public boolean sremove(int db, String key, String... element) {
        if (element == null) {
            return false;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        boolean success = (redis.srem(key, element) == 1);
        redis.close();
        return success;
    }

    public Set<String> sget(int db, String key) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<String> m = redis.smembers(key);
        redis.close();
        return m;
    }

    /**
     * 返回set的的元素個數
     *
     * @param key
     * @return
     * @Title: scard
     */
    public long scard(int db, String key) {
        Jedis redis = this.pool.getResource();
        long size = redis.scard(key);
        redis.close();
        return size;
    }

    /**
     * 測試元素是否存在
     *
     * @param key
     * @param element
     * @return
     */
    public boolean sismember(int db, String key, String element) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        boolean ret = redis.sismember(key, element);
        redis.close();
        return ret;
    }

    //    Redis 列表操作:laddList,lpush,rpush,lrange,lgetList,(lexist),lpop,lrem
    public void laddList(int db, String key, String... elements) {
        if (elements == null || elements.length == 0) {
            return;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        redis.lpush(key, elements);
        redis.close();
    }

    /**
     * 依次插入表頭
     *
     * @param key
     * @param elements
     * @Title: lpush
     */
    public void lpush(int db, String key, String... elements) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        redis.lpush(key, elements);
        redis.close();
    }


    /**
     * 依次插入表尾
     *
     * @param db
     * @param key
     * @param elements
     */
    public void rpush(int db, String key, String... elements) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        redis.rpush(key, elements);
        redis.close();
    }

    /**
     * 返回指定區間內的元素
     *
     * @param key
     * @param start
     * @param end
     * @return
     * @Title: lrange
     */
    public List<String> lrange(int db, String key, int start, int end) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        List<String> list = redis.lrange(key, start, end);
        redis.close();
        return list;
    }

    public List<String> lgetList(int db, String key) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        long len = redis.llen(key);
        List<String> ret = redis.lrange(key, 0, len - 1);
        redis.close();
        return ret;
    }

    /**
     * 列表list中是否包含value
     *
     * @param key
     * @param value
     * @return
     */
    public boolean lexist(int db, String key, String value) {
        List<String> list = lgetList(db, key);
        return list.contains(value);
    }

    public List<String> lgetList(int db, String key, long len) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        long max = redis.llen(key);
        long l = max > len ? len : max;
        List<String> ret = redis.lrange(key, 0, l - 1);
        redis.close();
        return ret;
    }

    public String lpop(int db, String key) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        String value = redis.lpop(key);
        redis.close();
        return value;
    }

    /**
     * count > 0 : 從表頭開始向表尾搜尋,移除與 value 相等的元素,數量為 count。
     * count < 0 : 從表尾開始向表頭搜尋,移除與 value 相等的元素,數量為 count 的絕對值。
     * count = 0 : 移除表中所有與 value 相等的值。
     *
     * @param db
     * @param key
     * @param count
     * @param value
     */
    public void lrem(int db, String key, int count, String value) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        redis.lrem(key, count, value);
        redis.close();
    }

    //    Redis 鍵操作:del,keys(delKeyLikes),exists
    public Long del(int db, String... keys) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Long cnt = redis.del(keys);
        redis.close();
        return cnt;
    }

    /**
     * 模糊刪除
     *
     * @param key
     * @return
     */
    public Long delKeyLikes(int db, String key) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<String> keys = redis.keys(key);
        Long cnt = redis.del(keys.toArray(new String[keys.size()]));
        redis.close();
        return cnt;
    }

    /**
     * 判斷某一個key值的儲存結構是否存在
     *
     * @param key
     * @return
     * @Title: exists
     */
    public boolean exists(int db, String key) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        boolean yes = redis.exists(key);
        redis.close();
        return yes;
    }

    //    Redis 有序集合操作:zadd,zincrby,zscore,zrevrank。。。

    public long zadd(int db, String key, int score, String member) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        long ret = 0;
        try {
            ret = redis.zadd(key, score, member);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            redis.close();
        }
        return ret;
    }

    /**
     * 新增 分數,並返回修改後的值
     *
     * @param key
     * @param update
     * @param member
     * @return
     */
    public double zincrby(int db, String key, int update, String member) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        double ret = redis.zincrby(key, update, member);
        redis.close();
        return ret;
    }

    /**
     * 返回有序集 key 中,成員 member 的 score 值,存在返回score,不存在返回-1
     *
     * @param key
     * @param member
     * @return
     */
    public double zscore(int db, String key, String member) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Double ret = redis.zscore(key, member);
        redis.close();
        if (ret == null) {
            return -1;
        }
        return ret;
    }

    /**
     * 按從大到小的排名,獲取 member的排名,最大排名為 0
     *
     * @param key
     * @param member
     * @return
     */
    public long zrevrank(int db, String key, String member) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        long ret = redis.zrevrank(key, member);
        redis.close();
        return ret;
    }

    /**
     * 按照score的值從小到大排序,返回member的排名,最小排名為 0
     *
     * @param key
     * @param member
     * @return 設定為名次從1開始。返回為-1,表示member無記錄
     * @Title: zrank
     */
    public long zrank(int db, String key, String member) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        long ret = -1;
        Long vv = redis.zrank(key, member);
        if (vv != null) {
            ret = vv.longValue();
        }
        redis.close();
        if (ret != -1) {
            ret += 1;
        }
        return ret;
    }

    /**
     * 【min, max】從小到大排序
     *
     * @param key
     * @param min
     * @param max
     * @return
     * @Title: zrangebyscore
     */
    public Set<String> zrangebyscore(int db, String key, long min, long max) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<String> ss = redis.zrangeByScore(key, min, max);
        redis.close();
        return ss;
    }

    public Set<String> zrange(int db, String key, long min, long max) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<String> ss = redis.zrange(key, min, max);
        redis.close();
        return ss;
    }

    /**
     * min 和 max 都是score的值,獲得一個包含了score的元組集合。元組(Tuple)
     * 笛卡爾積中每一個元素(d1,d2,…,dn)叫作一個n元組(n-tuple)或簡稱元組
     *
     * @param key
     * @param min
     * @param max
     * @return
     * @Title: zrangebyscorewithscores
     */
    public Set<Tuple> zrangebyscorewithscores(int db, String key, long min, long max) {
        Jedis redis = this.pool.getResource();
        if (redis == null) {
            return null;
        }
        redis.select(db);
        Set<Tuple> result = null;
        try {
            result = redis.zrangeByScoreWithScores(key, min, max);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            redis.close();
        }
        return result;
    }

    /**
     * zrevrangeWithScores : 從大到小排序 zrangeWithScores : 從小到大排序
     *
     * @param key
     * @param start : (排名)0表示第一個元素,-x:表示倒數第x個元素
     * @param end   : (排名)-1表示最後一個元素(最大值)
     * @return 返回 排名在start 、end之間帶score元素
     * @Title: zrangeWithScores
     */
    public Map<String, Double> zrevrangeWithScores(int db, String key, long start, long end) {
        Jedis redis = this.pool.getResource();
        if (redis == null) {
            return null;
        }
        redis.select(db);
        Set<Tuple> result = null;
        try {
            result = redis.zrevrangeWithScores(key, start, end);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            redis.close();
        }
        return tupleToMap(result);
    }

    public Map<String, Double> tupleToMap(Set<Tuple> tupleSet) {
        if (tupleSet == null)
            return null;
        Map<String, Double> map = new LinkedHashMap<>();
        for (Tuple tup : tupleSet) {
            map.put(tup.getElement(), tup.getScore());
        }
        return map;
    }

    /**
     * 刪除key中的member
     *
     * @param key
     * @param member
     * @return
     * @Title: zrem
     */
    public long zrem(int db, String key, String member) {
        Jedis redis = this.pool.getResource();
        if (redis == null) {
            return -1;
        }
        redis.select(db);
        long result = -1;
        try {
            result = redis.zrem(key, member);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            redis.close();
        }
        return result;
    }

    /**
     * 從高到低排名,返回前 num 個score和member
     *
     * @param key
     * @param num
     * @return
     */
    public Set<Tuple> ztopWithScore(int db, String key, int num) {
        if (num <= 0) {
            return null;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<Tuple> ret = redis.zrevrangeWithScores(key, 0, num - 1);
        redis.close();
        return ret;
    }

    /**
     * 返回score區間的member
     *
     * @param key
     * @param max
     * @param min
     * @return
     */
    public Set<String> zrevrangeByScore(int db, String key, int max, int min) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<String> ret = redis.zrevrangeByScore(key, max, min);
        redis.close();
        return ret;
    }

    /**
     * 從高到低排名,返回前 num 個
     *
     * @param key
     * @param num
     * @return
     */
    public Set<String> ztop(int db, String key, int num) {
        if (num <= 0) {
            return null;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<String> ret = redis.zrevrange(key, 0, num - 1);
        redis.close();
        return ret;
    }

    /**
     * 從高到低排名,返回start到end的前 num 個
     */
    public Set<String> ztop(int db, String key, int start, int end) {
        if (end <= start) {
            return null;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        Set<String> ret = redis.zrevrange(key, start, end - 1);
        redis.close();
        return ret;
    }

    /**
     * 返回zset的的元素個數
     *
     * @param key
     * @return
     * @Title: zcard_
     */
    public long zcard(int db, String key) {
        Jedis redis = this.pool.getResource();
        redis.select(db);
        long size = redis.zcard(key);
        redis.close();
        return size;
    }

    //    釋出,訂閱

    /**
     * 將資訊 message 傳送到指定的頻道 channel。
     *
     * @param db
     * @param channel
     * @param message
     */
    public void publish(int db, String channel, String message) {
        if (channel == null || message == null) {
            return;
        }
        Jedis redis = this.pool.getResource();
        redis.select(db);
        redis.publish(channel, message);
        redis.close();
    }
}

Redis 使用

import java.util.List;
import java.util.Map;
import java.util.Set;

public class RedisDemo {
    public static void main(String[] args) {
        RedisDemo demo = new RedisDemo();
        demo.run();
    }

    public void run() {
        Redis redis = Redis.getInstance();
        /** redis save **/
        System.out.println("=============redis save==============");
        // string save
        System.out.println("string save:呼叫set時,若key不存在則新增key,否則為修改key對應的值");
        redis.set(Redis.DB, "testKey1", "test string val1");
        // set save
        System.out.println("set save:set中的元素不允許出現重複且無序");
        redis.sadd(Redis.DB, "testKey2", "test set val1");
        redis.sadd(Redis.DB, "testKey2", "test set val2");
        redis.sadd(Redis.DB, "testKey2", "test set val3");
        // hash save
        System.out.println("hash save:呼叫hset時,若key不存在則建立key,若hash中存在這個hashkey,則修改其值,不存在則新增一條hash資料");
        redis.hset(Redis.DB, "testKey3", "hashKey1", "hashVal1");
        redis.hset(Redis.DB, "testKey3", "hashKey2", "hashVal2");
        redis.hset(Redis.DB, "testKey3", "hashKey3", "hashVal3");
        redis.hset(Redis.DB, "testKey3", "hashKey4", "hashVal4");
        // list save
        System.out.println("list save:資料在連結串列中是有序的,並可以重複新增資料");
        redis.lpush(Redis.DB, "testKey4", "test list val1");
        redis.lpush(Redis.DB, "testKey4", "test list val2");
        redis.lpush(Redis.DB, "testKey4", "test list val3");
        // sorted set save
        System.out.println("sorted set save:有序set中的元素是有序的");
        redis.zadd(Redis.DB, "testKey5", 1, "test zset val1");
        redis.zadd(Redis.DB, "testKey5", 2, "test zset val2");
        redis.zadd(Redis.DB, "testKey5", 3, "test zset val3");
        redis.zadd(Redis.DB, "testKey5", 4, "test zset val4");
        /** redis get **/
        System.out.println("=============redis get==============");
        // string get
        String stringRet = redis.get(Redis.DB, "testKey1");
        System.out.println("string get:" + stringRet);
        // set get
        Set<String> setRet = redis.sget(Redis.DB, "testKey2");
        System.out.print("set get:");
        for (String string : setRet) {
            System.out.print(string + ",");
        }
        System.out.println();
        // hash get
        String hashKeyRet = redis.hget(Redis.DB, "testKey3", "hashKey2");
        System.out.println("hash key get:" + hashKeyRet);
        Map<String, String> hashRet = redis.hgetAll(Redis.DB, "testKey3");
        System.out.print("hash get:");
        for (String string : hashRet.keySet()) {
            System.out.print("key[" + string + "]" + "value[" + hashRet.get(string) + "],");
        }
        System.out.println();
        // list get
        List<String> listRet = redis.lgetList(Redis.DB, "testKey4");
        System.out.print("list get:");
        for (String string : listRet) {
            System.out.println(string + ",");
        }
        // zset get
        long val2Rank = redis.zrank(Redis.DB, "testKey5", "test zset val2");
        System.out.println("zset get val2 rank:" + val2Rank);
        Set<String> zsetRet = redis.zrange(Redis.DB, "testKey5", 0, 3);
        System.out.print("zset get range:");
        for (String string : zsetRet) {
            System.out.println(string + ",");
        }
        /** redis delete **/
        System.out.println("=============redis delete==============");
        // string delete
        System.out.println("string delete:呼叫Redis的del方法,可直接刪除key,對於所有的資料型別來說,都可以通過這種方式直接刪除整個key");
        redis.del(Redis.DB, "testKey1");
        // set delete
        System.out.println("set delete:刪除set中的val3");
        redis.sremove(Redis.DB, "testKey2", "test set val3");
        // hash delete
        System.out.println("hash delete:刪除hash中key為hashKey4的元素");
        redis.hdel(Redis.DB, "testKey3", "hashKey4");
        // list delete
        System.out.println("list delete:刪除list中值為test list val3的元素,其中count引數,0代表刪除全部,正數代表正向刪除count個此元素,負數代表負向刪除count個此元素");
        redis.lrem(Redis.DB, "testKey4", 0, "test list val3");
        // zset delete
        System.out.println("zset delete:同set刪除元素的方式相同");
        redis.zrem(Redis.DB, "testKey5", "test zset val4");
        System.out.println("除了以上常用api之外,還有更多api,在Redis類中都有列出,請參考Redis類,或直接參照Jedis的官方文件");
    }
}