1. Jedis Lists Demos

对应redis命令参考:redis lists组命令

package samples.cache.jedis;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisDataException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;

/**
 * @author Zi Lai Ye
 * @date 2017/10/7
 */
public class JedisListTests {
    public static final Logger logger = LoggerFactory.getLogger(JedisListTests.class);

    public static final String HOST = "localhost";
    public static final int PORT = 6379;

    public static final String key = "mylist1";
    public static final int lsize = 10;
    public static final String OK = "OK";

    private Jedis jedis;

    @Before
    public void beforeClass() {
        jedis = new Jedis(HOST, PORT);
        jedis.flushDB();
    }

    @After
    public void afterClass() {
//        jedis.flushDB();
        jedis.close();
    }

    // lpush 将一个或多个值 value 插入到列表 key 的左侧(表头) lpush + lpop 即可实现先进后出的栈操作
    @Test
    public void lpush() {

        // 断言key不存在
        Boolean exists = jedis.exists(key);
        assertFalse(exists);

        // 对一个不存在的 key 进行 lpush 操作, 会先创建一个空列表, 然后再进行 lpush操作
        Long pushResult = jedis.lpush(key, "one");
        assertEquals(Long.valueOf(1), pushResult);
        jedis.lrem(key, 1, "one");

        // 依次在列表左侧插入1 2 3 4..., 得到的列表为插入顺序相反列表: ...4 3 2 1
        for (int i = 1; i <= lsize; i++) {
            jedis.lpush(key, String.valueOf(i));
        }

        // 判断长度
        Long llen = jedis.llen(key);
        assertEquals(Long.valueOf(lsize), llen);

        // 依次从右侧(即列表尾部)取出全部的列表元素, 判断其顺序是否为1 2 3 4 ...
        for (int i = 1; i <= lsize; i++) {
            String rpop = jedis.rpop(key);
            assertEquals(String.valueOf(i), rpop);
        }

        // 对非列表类型的 key 进行 lpush 操作, 返回错误
        jedis.set("key1", "value1");
        try {
            jedis.lpush("key1", "value2");
        } catch (Exception e) {
            logger.error("对非列表类型的 key 进行 lpush 操作, 返回错误", e);
        }
    }

    // lpushx 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。
    @Test
    public void lpushx() {
        // key 不存在
        Boolean exists = jedis.exists(key);
        assertFalse(exists);

        // 如果 key 不存在 , lpushx 什么也不做
        Long lpushxResult = jedis.lpushx(key, "one");
        assertEquals(Long.valueOf(0), lpushxResult);

        // 如果 key 类型不是列表, lpushx 返回错误
        jedis.set("key1", "v1");
        try {
            lpushxResult = jedis.lpushx("key1", "v2");
            assertEquals(Long.valueOf(0), lpushxResult);
        } catch (Exception e) {
            logger.error("如果 key 类型不是列表, lpushx 返回错误", e);
        }

        // 仅当 key 是一个列表时, 操作成功, 返回执行成功后表的长度
        jedis.lpush(key, "one");
        lpushxResult = jedis.lpushx(key, "two");
        assertEquals(Long.valueOf(2), lpushxResult);
    }

    // lpop 移除并返回列表 key 的头元素。
    @Test
    public void lpop() {
        // 断言 key 不存在
        Boolean exists = jedis.exists(key);
        assertFalse(exists);
        // 如果 key 不存在 , 返回 Null
        String lpopResult = jedis.lpop(key);
        assertNull(lpopResult);

        // 移除并返回列表 key 的头元素
        pushBatch();
        assertEquals(Long.valueOf(lsize), jedis.llen(key));

        String headElel = jedis.lindex(key, 0);
        String popElel = jedis.lpop(key);
        assertEquals(headElel, popElel); // 头元素为索引为0的元素
        assertEquals(Long.valueOf(lsize - 1), jedis.llen(key)); // 数量减1

        // 如果 key 类型不是列表, 返回错误信息
        jedis.set("key1", "v1");
        try {
            jedis.lpop("key1");
        } catch (Exception e) {
            logger.error("如果 key 类型不是列表, 返回错误信息", e);
        }
    }

    // rpush 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
    @Test
    public void rpush() {
        // 断言key不存在
        Boolean exists = jedis.exists(key);
        assertFalse(exists);

        // 对一个不存在的 key 进行 rpush 操作, 会先创建一个空列表, 然后再进行 rpush操作
        Long pushResult = jedis.rpush(key, "one");
        assertEquals(Long.valueOf(1), pushResult);
        jedis.lrem(key, 1, "one");

        // 在表尾插入元素
        for (int i = 1; i <= lsize; i++) {
            jedis.rpush(key, String.valueOf(i));
        }
        assertEquals(Long.valueOf(lsize), jedis.llen(key));
        for (int i = 1; i <= lsize; i++) {
            String lpopElem = jedis.lpop(key);
            assertEquals(String.valueOf(i), lpopElem);
        }

        // 对非列表类型的 key 进行 rpush 操作, 返回错误
        jedis.set("key1", "value1");
        try {
            jedis.rpush("key1", "value2");
        } catch (Exception e) {
            logger.error("对非列表类型的 key 进行 rpush 操作, 返回错误", e);
        }
    }

    // llen 获取列表的长度
    @Test
    public void llen() {
        // 1. 不存在的列表 长度为0
        Long llen = jedis.llen(key);
        assertEquals(Long.valueOf(0), llen);
        logger.info("不存在的key进行llen操作, 被认定为空列表, 返回长度为0");

        // 2. 已存在的列表, 返回其长度
        pushBatch();
        llen = jedis.llen(key);
        assertEquals(Long.valueOf(lsize), llen);

        // 3. 非列表类型的key,返回错误
        jedis.set("key1", "value1");
        try {
            llen = jedis.llen("key1");
        } catch (JedisDataException ex) {
            logger.error("对非列表类型的key进行llen操作, 返回错误", ex);
        }
    }

    // 将列表 key 下标为 index 的元素的值设置为 value 。
    @Test
    public void lset() {
        String newValue;
        // lset 对不存在的 key 进行操作, 返回错误 , no such key
        try {
            newValue = jedis.lset(key, 0, "newValue");
        } catch (Exception ex) {
            logger.error("对不存在的 key 进行操作, 返回错误 ", ex);
        }
        // lset对已存在的key操作成功, 返回OK
        pushBatch();
        newValue = jedis.lset(key, 0, "newValue");
        assertEquals(OK, newValue);

        // 索引超出范围, 报错
        try {
            jedis.lset(key, lsize, "test");
        } catch (Exception e) {
            logger.info("超出索引范围, 报错", e);
        }

        // 类型不是列表, 返回错误
        jedis.set("key1", "1");
        try {
            jedis.lset("key1", 0, "");
        } catch (Exception e) {
            logger.info("类型不是列表, 返回错误", e);
        }
    }

    // 返回列表 key 中,下标为 index 的元素。
    @Test
    public void lindex() {
        // key 不存在
        Boolean exists = jedis.exists(key);
        assertFalse(exists);

        // key 不存在时, 返回  null
        String lindexResult = jedis.lindex(key, 0);
        assertNull(lindexResult);

        pushBatch();
        // 返回下标为index的元素
        int revertIndex = lsize * -1;
        for (int i = 0; i < lsize; i++) {
            assertEquals(String.valueOf(i + 1), jedis.lindex(key, i));
            assertEquals(String.valueOf(i + 1), jedis.lindex(key, revertIndex++));
        }

        // 如果 key 类型不是列表, 返回错误
        jedis.set("key1", "v1");
        try {
            jedis.lindex("key1", 0);
        } catch (Exception e) {
            logger.error("如果 key 类型不是列表, 返回错误", e);
        }
    }

    // linsert: 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
    @Test
    public void linsert() {
        Boolean exists = jedis.exists(key);
        assertFalse(exists);

        // key 不存在或为空列表, 返回 0
        Long linsertResult = jedis.linsert(key, BinaryClient.LIST_POSITION.BEFORE, "1", "0");
        assertEquals(Long.valueOf(0), linsertResult);

        // key 存在, 将值插入到列表 key 当中, 位于指定值 之前
        pushBatch();
        assertEquals(Long.valueOf(lsize), jedis.llen(key));

        linsertResult = jedis.linsert(key, BinaryClient.LIST_POSITION.BEFORE, "1", "0");
        assertEquals(Long.valueOf(lsize + 1), jedis.llen(key)); // 插入成功, 长度+1
        assertEquals("0", jedis.lindex(key, 0)); // 第一个元素

        // 如果指定值 pivot 不存在, 返回 -1
        linsertResult = jedis.linsert(key, BinaryClient.LIST_POSITION.AFTER, "12", "13");
        assertEquals(Long.valueOf(-1), linsertResult);

        // 如果 key 的类型不是列表, 异常错误
        jedis.set("key1", "v1");

        try {
            jedis.linsert("key1", BinaryClient.LIST_POSITION.AFTER, "1", "2");
        } catch (Exception e) {
            logger.error("如果 key 的类型不是列表, 异常错误", e);
        }
    }

    // lrem remove。根据参数 count 的值,移除列表中与参数 value 相等的元素。
    @Test
    public void lrem() {
        Boolean exists = jedis.exists(key);
        assertFalse(exists);

        // 不存在的 key 进行 lrem, 被视为空列表移除, 返回 移除数量 0
        Long lremResult = jedis.lrem(key, 0L, "1");
        assertEquals(Long.valueOf(0), lremResult);

        // 插入 1-10 的列表 两遍
        pushBatch();
        pushBatch();

        // 参数 count > 0 , 从左向右移除count个 value
        lremResult = jedis.lrem(key, 1, "1");
        assertEquals(Long.valueOf(1), lremResult); // 移除1个
        assertEquals("2", jedis.lindex(key, 0)); // 第1个元素变成 2
        jedis.del(key);

        pushBatch();
        pushBatch();
        // 参数 count = 0 , 移除列表中所有与value相等的值
        lremResult = jedis.lrem(key, 0, "2");
        assertEquals(Long.valueOf(2), lremResult); // 移除2个
        assertEquals(Long.valueOf(lsize * 2 - 2), jedis.llen(key)); // 数量少了2个

        jedis.del(key);
        pushBatch();
        pushBatch();
        // 参数 count < 0, 从右向左移除 count 个 value
        lremResult = jedis.lrem(key, -2, "3");
        assertEquals(Long.valueOf(2), lremResult);
        assertEquals(Long.valueOf(lsize * 2 - 2), jedis.llen(key));

        // 如果 key 不是列表类型, 抛出异常
        jedis.set("key1", "v1");
        try {
            jedis.lrem(key, 0, "1");
        } catch (Exception e) {
            logger.error("如果 key 不是列表类型, 抛出异常", e);
        }
    }

    // ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
    @Test
    public void ltrim() {
        Boolean exists = jedis.exists(key);
        assertFalse(exists);

        // 如果 key 不存在, 认为修剪成功, 返回OK
        String ltrimResult = jedis.ltrim(key, 0, -1);
        assertEquals(OK, ltrimResult);

        pushBatch();
        // 如果 key 存在, 返回 start-top之间的元素, 其它元素全部移除
        ltrimResult = jedis.ltrim(key, 0, 4);
        assertEquals(OK, ltrimResult);
        assertEquals(Long.valueOf(5), jedis.llen(key));

        jedis.del(key);
        pushBatch();
        // 超出范围的下标不会报错, 如果 start 超范围, 或者 start > stop , 都会把整个列表清空
        ltrimResult = jedis.ltrim(key, lsize, 5);
        assertEquals(OK, ltrimResult);
        assertEquals(Long.valueOf(0), jedis.llen(key));

        // 如果 key 类型不是列表, 报错
        jedis.set("key1", "v1");

        try {
            jedis.ltrim("key1", 0, -1);
        } catch (Exception e) {
            logger.error("如果 key 类型不是列表, 报错", e);
        }
    }

    // blpop 是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,
    // 直到等待超时或发现可弹出元素为止。
    @Test
    public void blpop() throws InterruptedException {
        jedis.lpush(key, "one");

        // 如果指定了多个 key , 则从左到右依次查找, 找到第一个非空列表, 执行lpop操作, 并将 key -value 返回
        List<String> blpopResults = jedis.blpop(20, key, "list0", "list1", "list2");
        assertEquals(2, blpopResults.size());
        assertEquals(key, blpopResults.get(0));
        assertEquals("one", blpopResults.get(1));
        assertEquals(Long.valueOf(0), jedis.llen(key));

        // 如果指定的多个 key 都不存在或为空列表, 则阻塞指定时间, 等待有新元素或超时为止
        new Thread(new Runnable() {
            public void run() {
                logger.info("开启新线程开始 blpop...");
                List<String> blpopResponses = jedis.blpop(10, key, "list0", "list1", "list2");
                if (blpopResponses != null && blpopResponses.size() > 0) {
                    logger.info("blpop 监听到新的元素, lpop key:{} result:{}", blpopResponses.get(0), blpopResponses.get(1));
                } else {
                    logger.info("blpop 阻塞时间到, 超时");
                }
            }
        }).start();
        logger.info("在 监听的 key 中 push 一个值...");
        jedis.lpush(key, "hello, any one here?");

        Thread.sleep(20000L);
    }

    private void pushBatch() {
        for (int i = 1; i <= lsize; i++) {
            jedis.rpush(key, String.valueOf(i));
        }
    }
}
Copyright © wychuan.com 2017 all right reserved,powered by Gitbook该文件修订时间: 2017-10-17 02:48:52

results matching ""

    No results matching ""