Jedis

概述

Jedis:一款java操作redis数据库的工具。是Redis官方推荐的Java连接开发工具。要在Java开发中使用好Redis中间件,必须对Jedis熟悉才能写成漂亮的代码。

使用java连接Redis时,要在Redis的配置文件中设置bind 0.0.0.0

Jedis所需的jar包依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.1.0</version>
</dependency>

基本使用

//1. 获取连接
Jedis jedis = new Jedis("localhost",6379);
//2. 操作
jedis.set("username","zhangsan");
//3. 关闭连接
jedis.close();

测试连通性

Jedis的基本使用非常简单,只需要创建Jedis对象的时候指定host,port, password即可。当然,Jedis对象有很多构造方法,都大同小异,只是对应和Redis连接的socket的参数不一样而已。

public class TestRedisPing {
    public static void main(String[] args) {
        //创建连接
        Jedis jedis=new Jedis("192.168.81.130", 6379);
        //设置密码 如果没有密码可以不设置
        jedis.auth("123456");
        //调用 ping方法
        String ping = jedis.ping();
        //输出PONG
        System.out.println(ping);
        jedis.close();
    }
}

Jedis操作Redis中的数据结构

key

public static void main(String[] args) {
    //创建连接
    Jedis jedis=new Jedis("192.168.81.130", 6379);
    //keys *
    Set<String> keys = jedis.keys("*");
    for (String key : keys) {
        System.out.println(key);
    }
    //判断是否存在k2
    System.out.println("是否存在k2" + jedis.exists("k2"));
    jedis.close();
}

string

package com.coydone.redistest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;

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

public class RedisTest {
    private Jedis jedis;
    @Before
    public void beforeRedis(){
        //1. 获取连接
        jedis=new Jedis("192.168.81.130", 6379);
    }
    @After
    public void afterRedis(){
        //3. 关闭连接
        jedis.close();
    }
    //keys * 查询所有的key
    @Test
    public void testKeys(){
        Set<String> keys = jedis.keys("*");
        for (String key : keys) {
            System.out.println(key);
        }
    }

    //string操作
    @Test
    public void testString(){
        //2. 操作
        //存储
        jedis.set("username","zhangsan");
        //获取
        String username = jedis.get("username");
        System.out.println(username);

        //可以使用setex()方法存储可以指定过期时间的 key value
        //将activecode:hehe键值对存入redis,并且20秒后自动删除该键值对
        jedis.setex("activecode",20,"hehe");

        jedis.mset("str1", "v1", "str2", "v2", "str3", "v3");
        System.out.println(jedis.mget("str1", "str2", "str3"));
    }
}

hash

@Test
public void testHash(){
    // 存储hash
    jedis.hset("user","name","lisi");
    jedis.hset("user","age","23");
    jedis.hset("user","gender","female");

    // 获取hash
    String name = jedis.hget("user", "name");
    System.out.println(name);

    // 获取hash的所有map中的数据
    Map<String, String> user = jedis.hgetAll("user");
    for (String value : user.values()) {
        System.out.println(value);
    }
}

list

@Test
public void testList(){
    //存储
    jedis.lpush("mylist","a","b","c");//从左边存
    jedis.rpush("mylist","a","b","c");//从右边存
    //范围获取
    List<String> list = jedis.lrange("mylist", 0, -1);
    for (String element : list) {
        System.out.println(element);
    }
    //弹出
    String element1 = jedis.lpop("mylist");//c
    System.out.println(element1);
}

set

@Test
public void testSet(){
    // set 存储
    jedis.sadd("myset","java","php","c++");

    //移除
    jedis.srem("myset", "php");
    System.out.println(jedis.smembers("myset").size());

    // set 获取
    Set<String> myset = jedis.smembers("myset");
    System.out.println(myset);
}

zset

//zset 即为 sortedset
@Test
public void testZset(){
    // sortedset 存储
    jedis.zadd("mysortedset",3,"亚索");
    jedis.zadd("mysortedset",30,"劫");
    jedis.zadd("mysortedset",55,"永恩");

    // sortedset 获取
    Set<String> mysortedset = jedis.zrange("mysortedset", 0, -1);

    System.out.println(mysortedset);
}

事务提交

基本操作

public class TestReidsTranaction {
    public static void main(String[] args) {
        // 创建连接
        Jedis jedis = new Jedis("192.168.81.130", 6379);
         //监控key,如果改动了事务就被放弃
         /*
         jedis.watch("serialNum");
         jedis.set("serialNum","s#####################");
         jedis.unwatch();*/
         Transaction transaction = jedis.multi();//被当作一个命令进行执行
         Response<String> response = transaction.get("serialNum");
         transaction.set("serialNum","s002");
         response = transaction.get("serialNum");
         transaction.lpush("list3","a");
         transaction.lpush("list3","b");
         transaction.lpush("list3","c");
         transaction.exec();
         //2 transaction.discard();
         System.out.println("serialNum***"+response.get());
        jedis.close();
    }
}

事务加锁

public class TestReidsTranactionLock {
    public boolean transMethod() {
        Jedis jedis = new Jedis("192.168.81.130", 6379);
        int balance;// 可用余额
        int debt;// 欠额
        int amtToSubtract = 10;// 实刷额度
        jedis.watch("balance");
        // jedis.set("balance","5");//此句不该出现,讲课方便。模拟其他程序已经修改了该条目
        balance = Integer.parseInt(jedis.get("balance"));
        if (balance < amtToSubtract) {
            jedis.unwatch();
            System.out.println("modify");
            jedis.close();
            return false;
        } else {
            System.out.println("***********transaction");
            Transaction transaction = jedis.multi();
            transaction.decrBy("balance", amtToSubtract);
            transaction.incrBy("debt", amtToSubtract);
            transaction.exec();
            balance = Integer.parseInt(jedis.get("balance"));
            debt = Integer.parseInt(jedis.get("debt"));
            System.out.println("*******" + balance);
            System.out.println("*******" + debt);
            jedis.close();
            return true;
        }
    }
    /**
     * 通俗点讲,watch命令就是标记一个键,如果标记了一个键, 在提交事务前如果该键被别人修改过,那事务就会失败,这种情况通常可以在程序中 重新再尝试一次。
     * 首先标记了键balance,然后检查余额是否足够,不足就取消标记,并不做扣减; 足够的话,就启动事务进行更新操作,
     * 如果在此期间键balance被其它人修改, 那在提交事务(执行exec)时就会报错, 程序中通常可以捕获这类错误再重新执行一次,直到成功。
     */
    public static void main(String[] args) {
        TestReidsTranactionLock test = new TestReidsTranactionLock();
        boolean retValue = test.transMethod();
        System.out.println("main retValue-------: " + retValue);
    }
}

主从复制

public class TestReidsMS {
    public static void main(String[] args) throws InterruptedException {
        // 创建连接
        Jedis jedis_M = new Jedis("192.168.120.129", 6379);
        Jedis jedis_S = new Jedis("192.168.120.129", 6380);
        jedis_S.slaveof("127.0.0.1", 6379);
        jedis_M.set("k6", "v6");
        Thread.sleep(500);
        System.out.println(jedis_S.get("k6"));
        jedis_M.close();
        jedis_S.close();
    }
}

集群连接

public class ClusterConnection{
    public static final String HOST = "192.168.81.130";
    public static final Integer HOST_IP = "7001";
    public static void main(String[] args){
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort(HOST,7001));
        nodes.add(new HostAndPort(HOST,7002));
        nodes.add(new HostAndPort(HOST,7003));
        nodes.add(new HostAndPort(HOST,7004));
        nodes.add(new HostAndPort(HOST,7005));
        nodes.add(new HostAndPort(HOST,7006));
        
        JedisCluster jedisCluster = new JedisCluster(nodes);
        jedisCluster.set("name","zhangsan");
        System.out.println(jedisCluster.get("name"));
        
        //关闭连接
        jedisCluster.close();
	}
}

jedis连接池

jedis连接池是基于apache-commons pool2实现的。在构建连接池对象的时候,需要提供池对象的配置对象,及JedisPoolConfig(继承自GenericObjectPoolConfig)。我们可以通过这个配置对象对连接池进行相关参数的配置(如最大连接数,最大空数等)。

JedisPool使用

package com.coydone.redistest;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

//1. 创建JedisPool连接池对象
//2. 调用方法 getResource()方法获取Jedis连接
public class RedisPoolTest {
    public static void main(String[] args) {
        //0.创建一个配置对象
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(50);
        config.setMaxIdle(10);

        //1.创建Jedis连接池对象
        JedisPool jedisPool = new JedisPool(config,"192.168.81.130",6379);

        //2.获取连接
        Jedis jedis = jedisPool.getResource();
        //3. 使用
        jedis.set("name","zhangsan");
        System.out.println(jedis.get("name"));

        //4. 关闭 归还到连接池中
        jedis.close();
    }
}

使用redis存储对象

public class JedisPoolApp {
    public static void main(String[] args) {
        JedisPoolConfig config = new JedisPoolConfig();
        //配置连接池的相关信息
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxIdle(80);
        poolConfig.setMinIdle(20);
        poolConfig.setMaxWaitMillis(2000);
        JedisPool jedisPool=new JedisPool(config,"192.168.81.130",6379);
        //从连接池里面得到连接
        Jedis jedis = jedisPool.getResource();
        //User类:name address
        User user =new User("小明","武汉");
		//使用fastjson:对象转json字符串
        jedis.set("user:1", JSON.toJSONString(user));
        String json = jedis.get("user:1");
        System.out.println(json);
        //json转对象
        User user1=JSON.parseObject(json,User.class);
        System.out.println(user1.getName()+"  "+user1.getAddress());
        jedis.close();//还到池里面
    }
}

连接池工具类

//需要加载配置文件jedis.properties
public class JedisPoolUtils {
    private static JedisPool jedisPool;
    static{
        //读取配置文件
        InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
        //创建Properties对象
        Properties pro = new Properties();
        //关联文件
        try {
            pro.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取数据,设置到JedisPoolConfig中
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
        config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle")));

        //初始化JedisPool
        jedisPool = new JedisPool(config,pro.getProperty("host"),Integer.parseInt(pro.getProperty("port")));
    }
    /**
	* 获取连接方法
	*/
    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}
//直接在代码里进行配置
public class JedisPoolUtil {
    private static volatile JedisPool jedisPool = null;// 被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存。
    private JedisPoolUtil() {
    }
    public static JedisPool getJedisPoolInstance() {
        if (null == jedisPool) {
            synchronized (JedisPoolUtil.class) {
                if (null == jedisPool) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxTotal(1000);
                    poolConfig.setMaxIdle(32);
                    poolConfig.setMaxWaitMillis(100 * 1000);
                    poolConfig.setTestOnBorrow(true);
                    jedisPool = new JedisPool(poolConfig, "192.168.120.129", 6379);
                }
            }
        }
        return jedisPool;
    }
    public static void release(JedisPool jedisPool, Jedis jedis) {
        if (null != jedis) {
            Jedis jedis2 = null;
            try {
                jedis2 = jedisPool.getResource();
            } finally {
                jedis2.close();
            }
        }
    }
}

//使用
public class TestJedisPool {
    public static void main(String[] args) {
        JedisPool jedisPool = JedisPoolUtil.getJedisPoolInstance();
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.set("k18", "v183");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JedisPoolUtil.release(jedisPool, jedis);
        }
    }
}

JedisPool配置

JedisPool的配置参数大部分是由JedisPoolConfig的对应项来赋值的。

maxTotal/maxActive:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted。
maxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
whenExhaustedAction:表示当pool中的jedis实例都被allocated完时,pool要采取的操作;默认有三种。
WHEN_EXHAUSTED_FAIL --> 表示无jedis实例时,直接抛出NoSuchElementException;
WHEN_EXHAUSTED_BLOCK --> 则表示阻塞住,或者达到maxWait时抛出JedisConnectionException;
WHEN_EXHAUSTED_GROW --> 则表示新建一个jedis实例,也就说设置的maxActive无用;
setMaxWaitMillis/maxWait:表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛JedisConnectionException;
testOnBorrow:获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;

testOnReturn:return 一个jedis实例给pool时,是否检查连接可用性(ping());

testWhileIdle:如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;

timeBetweenEvictionRunsMillis:表示idle object evitor两次扫描之间要sleep的毫秒数;

numTestsPerEvictionRun:表示idle object evitor每次扫描的最多的对象数;

minEvictableIdleTimeMillis:表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;

softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。如果为-1,evicted不会根据idle time驱逐任何对象。如果minEvictableIdleTimeMillis>0,则此项设置无意义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义;

lifo:borrowObject返回对象时,是采用DEFAULT_LIFO(last in first out,即类似cache的最频繁使用队列),如果为False,则表示FIFO队列;
====================================================================
其中JedisPoolConfig对一些参数的默认设置如下:
testWhileIdle=true
minEvictableIdleTimeMills=60000
timeBetweenEvictionRunsMillis=30000
numTestsPerEvictionRun=-1
coydone的博客
原文地址:https://www.cnblogs.com/coydone/p/13920928.html