Redis筆記3:Jedis連線自動釋放

zhenghaishu發表於2016-01-17


一、正常釋放連線

正常釋放連線的程式碼如下:

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;


public class JedisTest {


    public static void main(String[] args) {

        JedisPoolConfig config = new JedisPoolConfig();


        //最大連線數, 應用自己評估,不要超過AliCloudDB for Redis每個例項最大的連線數

        config.setMaxTotal(5);


        String host = "Your real hostname or host ip";

        String password = "Your real password";

        JedisPool pool = new JedisPool(config, host, 6379, 3000, password);

        Jedis jedis = null;

        for(int i = 0; i < 10; i++) {

            try {

                jedis = pool.getResource();

                jedis.set("foo", "bar");

                System.out.println("第" + (i+1) + "個連線, 得到的值為" + jedis.get("foo"));

            } finally {

                if (jedis != null) {

                    jedis.close();

                }

            }

        }


        pool.close();

    }

}


執行結果:

1個連線, 得到的值為bar

2個連線, 得到的值為bar

3個連線, 得到的值為bar

4個連線, 得到的值為bar

5個連線, 得到的值為bar

6個連線, 得到的值為bar

7個連線, 得到的值為bar

8個連線, 得到的值為bar

9個連線, 得到的值為bar

10個連線, 得到的值為bar


分析:這裡透過config.setMaxTotal(5);把連線池的最大連線設為五個,測試的時候在迴圈裡啟用了10個連線,並都正常列印出了結果。這是因為jedis連線用完了就關閉的緣故。注意到這裡使用單執行緒進行測試,連線池的最大連線數設為1就能滿足需求。


二、忘記釋放連線

有時候程式設計師有可能忘了關閉連線,程式碼如下:

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;


public class JedisTest {


    public static void main(String[] args) {

        JedisPoolConfig config = new JedisPoolConfig();


        //最大連線數, 應用自己評估,不要超過AliCloudDB for Redis每個例項最大的連線數

        config.setMaxTotal(5);


        String host = "Your real hostname or host ip";

        String password = "Your real password";

        JedisPool pool = new JedisPool(config, host, 6379, 3000, password);

        Jedis jedis = null;

        for(int i = 0; i < 10; i++) {

            try {

                jedis = pool.getResource();

                jedis.set("foo", "bar");

                System.out.println("第" + (i+1) + "個連線, 得到的值為" + jedis.get("foo"));

            } finally {

                if (jedis != null) {

//                  jedis.close();

                }

            }

        }


        pool.close();

    }

}


執行結果:

1個連線, 得到的值為bar

2個連線, 得到的值為bar

3個連線, 得到的值為bar

4個連線, 得到的值為bar

5個連線, 得到的值為bar


分析:這個程式碼跟上一步的程式碼比起來,只是把redis.close();這一行註釋起來了,相當於程式設計師忘寫這行程式碼。導致的結果就是隻能得到5個結果。這是因為連線池的最大連線數設為5,然後測試時啟用了10個連線,因為連線沒有被釋放,當最大連線數被用完後,後面的5個連線就連不上了,只能乾等著。


三、將Jedis的連線和釋放進行封裝

為了避免上述忘記釋放連線的情況,我們們可以把連線的程式碼封裝到RedisUtil類裡,在RedisUtil內部實現釋放連線的邏輯,這樣程式設計師在外部呼叫的時候不需要釋放也無法釋放,從而達到了安全連線的目的。

封裝程式碼如下:

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;


/**

 * @功能:Redis通用類

 * @作者:鄭海樹

 * @日期:2016117

 */

public class RedisUtil {


    private JedisPool pool = null;


    /**

     * @功能:帶引數的建構函式

     * @引數:host,主機名或主機IP

     * @引數:port,埠

     * @引數:password,訪問Redis資料庫的密碼

     */

    public RedisUtil(String host, int port, String password) {

        if (pool == null) {

            JedisPoolConfig config = new JedisPoolConfig();

            // 控制一個pool可分配多少個jedis例項,透過pool.getResource()來獲取;

            // 如果賦值為-1,則表示不限制;如果pool已經分配了maxTotaljedis例項,則此時pool的狀態為exhausted(耗盡)

            config.setMaxTotal(1);

            pool = new JedisPool(config, host, port, 60000, password);

        }

    }


    /**

     * @功能:透過Rediskey獲取值,並釋放連線資源

     * @引數:key,鍵值

     * @返回: 成功返回value,失敗返回null

     */

    public String get(String key){

        Jedis jedis = null;

        String value = null;

        try {

            jedis = pool.getResource();

            value = jedis.get(key);

        } catch (Exception e) {

            pool.returnBrokenResource(jedis);

            e.printStackTrace();

        } finally {

            if(null != pool) {

                pool.returnResource(jedis);        

            }

        }

        return value;

    }


    /**

     * @功能:向redis存入keyvalue(如果key已經存在 則覆蓋),並釋放連線資源

     * @引數:key,鍵

     * @引數:value,與key對應的值

     * @返回:成功返回“OK”,失敗返回“0”

     */

    public String set(String key,String value){

        Jedis jedis = null;

        try {

            jedis = pool.getResource();

            return jedis.set(key, value);

        } catch (Exception e) {

            pool.returnBrokenResource(jedis);

            e.printStackTrace();

            return "0";

        } finally {

            if(null != pool) {

                pool.returnResource(jedis);        

            }

        }

    }

}


測試程式碼:

public class RedisUtilTest {


    public static void main(String[] args) {

        String host = "Your real hostname or host ip";

        String password = "Your real password";

        int port = 6379;

        RedisUtil redisUtil = new RedisUtil(host, port, password);

        for(int i = 0; i < 10; i++) {

            redisUtil.set("foo", "bar");

            System.out.println("第" + (i+1) + "個連線, 得到的值為" + redisUtil.get("foo"));

        }

    }


}


執行結果:

1個連線, 得到的值為bar

2個連線, 得到的值為bar

3個連線, 得到的值為bar

4個連線, 得到的值為bar

5個連線, 得到的值為bar

6個連線, 得到的值為bar

7個連線, 得到的值為bar

8個連線, 得到的值為bar

9個連線, 得到的值為bar

10個連線, 得到的值為bar


分析:在RedisUtil中特意把最大連線數設為1,且在setget方法中實現了釋放連線的邏輯。這樣,在不考慮多執行緒的情況下,10個迴圈可以反覆利用一個連線。


四、後續工作

1 在實際專案中,多數情況下遇到的是併發連線的情況,應該利用多執行緒寫一個併發測試,並且增大引數來判斷效率問題。

2 這裡的RedisUtil僅實現了最基本的功能,可考慮將其擴充套件成一個通用類。這樣程式設計師在處理Redis連線的時候,統一跟RedisUtil打交道即可,不需要再訪問Jedis.classJedisPool.class



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29485627/viewspace-1977880/,如需轉載,請註明出處,否則將追究法律責任。

相關文章