使用JedisAPI操作Redis以及Jedis实现Redis事务


以下总结了关于Redis比较全面的知识笔记以及面试题,方便自己复习的同时希望对大家有所帮助。

序号 内容 链接地址
1 Redis的基础知识、单机版安装、数据类型介绍(老版本) https://blog.csdn.net/weixin_43246215/article/details/107474283
2 Redis常用命令、配置文件介绍、数据持久化方式、集群搭建 (老版本) https://blog.csdn.net/weixin_43246215/article/details/107947562
3 Redis的五种常用数据类型、三种特殊数据类型详解 https://blog.csdn.net/weixin_43246215/article/details/108041739
4 Redis基本的事务操作以及使用Redis实现乐观锁 https://blog.csdn.net/weixin_43246215/article/details/108045931
5 使用JedisAPI操作Redis以及Jedis实现Redis事务 https://blog.csdn.net/weixin_43246215/article/details/108067542
6 Redis的配置文件详解(中文) https://blog.csdn.net/weixin_43246215/article/details/108068245
7 Redis数据持久化的两种方式以及Redis实现订阅发布 https://blog.csdn.net/weixin_43246215/article/details/108068797
8 Redis的伪集群搭建以及主从复制原理 https://blog.csdn.net/weixin_43246215/article/details/108069472
9 Redis中哨兵(Sentinel)模式的使用以及相关配置介绍 https://blog.csdn.net/weixin_43246215/article/details/108088179
10 Redis中的缓存穿透、缓存击穿以及缓存雪崩(理论知识) https://blog.csdn.net/weixin_43246215/article/details/108089026
11 Spring整合Redis实现查询缓存以及同步缓存 待更新
12 SpringBoot整合Redis以及自定义Redis Template https://blog.csdn.net/weixin_43246215/article/details/108476328
13 Redis常见面试题 https://blog.csdn.net/weixin_43246215/article/details/108090095
14 待更新

概括

Jedis是Redis官方提供的Java连接开发工具,使用Java操作Redis的中间件,其实就是一个jar包,里面集成了 redis 的一些命令操作,封装了对 redis 命令的 Java 客户端,如果要使用Java操作Redis,那么一定要熟悉Jedis。

Jedis的基本使用

首先我们创建一个Maven项目进行测试。

1、导包

<!--导入Jedis包-->
    <dependencies>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>
    </dependencies>

2、测试ping

  • 接下来便是进行代码的测试
public class TestPing {
    public static void main(String[] args) {
        //(1) new Jedis对象
        Jedis jedis = new Jedis("192.168.15.133",6379);
        //(2)Jedis对象中的方法就是之前学过的命令
        System.out.println( jedis.ping() );
        //(3)断开连接
        jedis.close();
    }
}
  • 输出:
    在这里插入图片描述
  • 步骤:
    首先连接数据库,创建Jedis对象,然后调用Jedis对象中的对应方法进行测试,最后测试完毕要断开连接。

3、测试Key

public static void main(String[] args) {
    Jedis jedis = new Jedis("192.168.15.133",6379);

    System.out.println("清空数据:"+jedis.flushDB());
    System.out.println("判断某个键是否存在:"+jedis.exists("username"));
    System.out.println("新增<'username','oldou'>的键值对:"+jedis.set("username","oldou"));
    System.out.println("新增<'password','123456'>的键值对:"+jedis.set("password","123456"));
    System.out.println("系统中所有的键如下所示:");
    Set<String> keys = jedis.keys("*");
    System.out.println(keys);
    System.out.println("删除键password:"+jedis.del("password"));
    System.out.println("判断键password是否存在:"+jedis.exists("password"));
    System.out.println("查看键username所存储的值类型:"+jedis.type("username"));
    System.out.println("随机返回key空间中的一个:"+jedis.randomKey());
    System.out.println("重命名key:"+jedis.rename("username","name"));
    System.out.println("获取修改后的name中的值:"+jedis.get("name"));
    System.out.println("按照索引查询:"+jedis.select(0));
    System.out.println("删除当前数据库中所有的key:"+jedis.flushDB());
    System.out.println("返回当前数据库中key的数目:"+jedis.dbSize());
    System.out.println("删除所有数据库中的所有key:"+jedis.flushAll());
    System.out.println("断开与Redis的连接:jedis.close()");
    jedis.close();
}
  • 输出:
    在这里插入图片描述

4、测试String类型

public class TestString {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.15.133",6379);

        jedis.flushDB();
        System.out.println("=====增加数据======");
        System.out.println(jedis.set("key1","value1"));
        System.out.println(jedis.set("key2","value2"));
        System.out.println(jedis.set("key3","value3"));
        System.out.println("查看所有的键:");
        Set<String> keys = jedis.keys("*");
        System.out.println(keys);
        System.out.println("删除key2:"+jedis.del("key2"));
        System.out.println("获取键key2:"+jedis.get("key2"));
        System.out.println("修改键key1中的值:"+jedis.set("key1","valuechanged"));
        System.out.println("获取key1中的值:"+jedis.get("key1"));
        System.out.println("在key3的后面加入值:"+jedis.append("key1","End..."));
        System.out.println("获取key3中的值:"+jedis.get("key3"));
        System.out.println("新增多个键值对:"+jedis.mset("k1","v1","k2","v2","k3","v3"));
        System.out.println("获取多个键值对:"+jedis.mget("k1","k2","k3"));
        System.out.println("删除多个键值对:"+jedis.del("k1","k2","k3"));
        System.out.println("获取多个键值对:"+jedis.mget("k1","k2","k3"));

        jedis.flushDB();
        System.out.println("============新增键值对防止覆盖原先值============");
        System.out.println(jedis.setnx("key1","value1"));
        System.out.println(jedis.setnx("key2","value2"));
        System.out.println(jedis.setnx("key2","value2-new"));
        System.out.println(jedis.get("key1")+"....."+jedis.get("key2"));

        System.out.println("=============新增键值对并设置有效时间=====================");
        System.out.println(jedis.setex("username",10,"oldou"));
        System.out.println(jedis.get("username"));
        try{
            TimeUnit.SECONDS.sleep(12);
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(jedis.get("username"));

        System.out.println("===============获取原值,更新为新值=================");
        System.out.println(jedis.getSet("key2","key2GetSet"));
        System.out.println(jedis.get("key2"));
        System.out.println("获取key2中值的字符串:"+jedis.getrange("key2",2,4));

        jedis.close();
    }
}

5、测试List类型

public class TestList {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.15.133",6379);
        jedis.flushDB();
        System.out.println("===========添加一个List===========");
        jedis.lpush("collections","ArrayList","LinkedList","vector","Stack","HashSet");
        jedis.lpush("collections","LinkedHashSet");
        jedis.lpush("collections","HashSet");
        jedis.lpush("collections","TreeSet");
        System.out.println("collections的内容:"+jedis.lrange("collections",0,-1));
        System.out.println("collections区间中0-3的元素:"+jedis.lrange("collections",0,3));
        System.out.println("=====================================");
        //删除列表中指定的值,第二个参数为删除的个数(有重复值时,后add进去的值先被删除,类似于出栈)
        System.out.println("删除指定元素个数:"+jedis.lrem("collections",2,"HashSet"));
        System.out.println("collections的内容:"+jedis.lrange("collections",0,-1));
        System.out.println("删除下标0-3区间之外的元素:"+jedis.ltrim("collections",0,3));
        System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
        System.out.println("collections列表出栈操作(左端):"+jedis.lpop("collection"));
        System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
        System.out.println("collections添加元素,从列表右端添加:"+jedis.rpush("collections","List","HashSet"));
        System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
        System.out.println("collections列表出栈操作(右端):"+jedis.rpop("collectiona"));
        System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
        System.out.println("修改collections指定下标1中的内容:"+jedis.lset("collections",1,"HashMap"));
        System.out.println("collections中的内容为:"+jedis.lrange("collections",0,-1));
        System.out.println("========================================");
        System.out.println("collections中的长度为:"+jedis.llen("collections"));
        System.out.println("获取collections下标为2的元素:"+jedis.lindex("collections",2));

        System.out.println("================================");
        jedis.lpush("sortedList","1","7","3","4","0","9");
        System.out.println("sortedList排序前:"+jedis.lrange("sortedList",0,-1));
        System.out.println(jedis.sort("sortedList"));
        System.out.println("sortedList排序后:"+jedis.lrange("sortedList",0,-1));

        jedis.flushDB();
        jedis.close();

    }

}

6、测试Set类型

public class TestSet {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.15.133",6379);

        jedis.flushDB();
        System.out.println("===============向集合中添加元素(不重复)================");
        System.out.println(jedis.sadd("eleSet","e1","e7","e3","e2","e5","e8"));
        System.out.println(jedis.sadd("eleSet","e6"));
        System.out.println(jedis.sadd("eleSet","e6"));
        System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
        System.out.println("删除一个元素e1:"+jedis.srem("eleSet","e1"));
        System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
        System.out.println("删除两个元素e6和e3:"+ jedis.srem("eleSet","e6","e3"));
        System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
        System.out.println("随机移除集合中的一个元素:"+jedis.spop("eleSet"));
        System.out.println("随机移除集合中的一个元素:"+jedis.spop("eleSet"));
        System.out.println("eleSet集合中所有的元素为:"+jedis.smembers("eleSet"));
        System.out.println("eleSet中包含的元素个数为:"+jedis.scard("eleSet"));
        System.out.println("e3是否在eleSet集合中:"+jedis.sismember("eleSet","e3"));
        System.out.println("e1是否在eleSet集合中:"+jedis.sismember("eleSet","e1"));
        System.out.println("e5是否在eleSet集合中:"+jedis.sismember("eleSet","e5"));
        System.out.println("============================================");
        System.out.println(jedis.sadd("mySet1","A","B","C","D","E","F","G"));
        System.out.println(jedis.sadd("mySet2","H","B","Q","D","G","U","L"));
        System.out.println("从mySet1中删除A元素并且存入mySet3中:"+jedis.smove("mySet1","mySet3","A"));
        System.out.println("从mySet2中删除H元素并且存入mySet3中:"+jedis.smove("mySet2","mySet3","H"));
        System.out.println("mySet1中的元素为:"+jedis.smembers("mySet1"));
        System.out.println("mySet3中的元素为:"+jedis.smembers("mySet3"));

        System.out.println("==================集合运算====================");
        System.out.println("mySet1中的元素为:"+jedis.smembers("mySet1"));
        System.out.println("mySet2中的元素为:"+jedis.smembers("mySet2"));
        System.out.println("mySet1和mySet2中的元素交集为:"+jedis.sinter("mySet1","mySet2"));
        System.out.println("mySet1和mySet2中的元素差集为:"+jedis.sunion("mySet1","mySet2"));
        System.out.println("mySet1和mySet2中的元素并集为:"+jedis.sdiff("mySet1","mySet2"));

        //将mySet1和mySet2的交集保存到mySet4集合当中
        jedis.sinterstore("mySet4","mySet1","mySet2");
        System.out.println("mySet4集合中的元素为:"+jedis.smembers("mySet4"));

        jedis.flushDB();
        jedis.close();

    }

}

7、测试Hash类型

public class TestHash {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.15.133",6379);
        jedis.flushDB();

        Map<String,String> map = new HashMap<>();
        map.put("key1","value1");
        map.put("key2","value2");
        map.put("key3","value3");
        map.put("key4","value4");

        //添加名称为hash(key)的hash元素。
        jedis.hset("hash",map);

        //向名称为hash的hash中添加key为key5,value为value5的元素
        jedis.hset("hash","key5","value5");
        System.out.println("散列表hash中的所有键值对为:"+jedis.hgetAll("hash"));
        System.out.println("散列表hash的所有键为:"+jedis.hkeys("hash"));
        System.out.println("散列表hash的所有键为:"+jedis.hvals("hash"));
        System.out.println("将key6保存的值加上一个整数,如果key6不存在就添加key6:"+jedis.hincrBy("hash","key6",10));
        System.out.println("散列表hash中所有的键值对为:"+jedis.hgetAll("hash"));
        System.out.println("将key6保存的值加上一个整数,如果key6不存在就添加key6:"+jedis.hincrBy("hash","key6",999));
        System.out.println("散列表hash中所有的键值对为:"+jedis.hgetAll("hash"));
        System.out.println("删除一个或者多个键值对:"+jedis.hdel("hash","key2"));
        System.out.println("散列表hash中所有的键值对为:"+jedis.hgetAll("hash"));
        System.out.println("散列表hash中键值对的个数为:"+jedis.hlen("hash"));
        System.out.println("散列表hash中是否存在key2:"+jedis.hexists("hash","key2"));
        System.out.println("散列表hash中是否存在key1:"+jedis.hexists("hash","key1"));
        System.out.println("获取散列表hash中的多个值:"+jedis.hmget("hash","key1","key5","key6"));
        jedis.flushDB();
        jedis.close();
    }

}

总结

Jedis基本使用比较简单,只需要在每次使用的时候,创建Jedis对象就可以了。当Jedis对象构建好时,Jedis的底层会打开一条Socket通道和Redis服务进行连接,因此在使用完Jedis对象之后,需要调用Jedis.close()方法把连接关闭,不然会占用系统CPU。当然,如果应用非常平凡的创建和销毁Jedis对象,对应用的性能是很大影响的,因为构建Socket的通道是很耗时的(类似数据库连接)。我们应该使用连接池来减少Socket对象的创建和销毁过程。

JedisPool(连接池)的使用

介绍

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

为什么要使用连接池?

Redis是一种非关系型数据库,基于C/S模式,如果需要使用Redis就必须要建立连接,由于C/S模式是一种远程通信的交互模式,因此Redis服务器可以单独作为一个数据库服务器来独立存在。假设Redis服务器与客户端分处在异地,虽然基于内存的Redis数据库有着超高的性能,但是底层的网络通信却占用了一次数据请求的大量时间,因为每次数据交互都需要先建立连接,假设一次数据交互总共用时30ms,超高性能的Redis数据库处理数据所花的时间可能不到1ms,也即是说前期的连接占用了29ms,连接池则可以实现在客户端建立多个链接并且不释放,当需要使用连接的时候通过一定的算法获取已经建立的连接,使用完了以后则还给连接池,这就免去了数据库连接所占用的时间。

连接池的使用

public static void testJedisPool() {
     //创建连接池对象
      JedisPool pool = new JedisPool("192.168.15.128",6379);
      //通过连接池获取Jedis对象
      Jedis jedis = pool.getResource();
      String hre = jedis.hget("user", "usrname");
      System.out.println(hre);
      jedis.close();
      pool.close();          
}

使用Jedis连接池之后,在每次用完连接对象后一定要记得把连接归还给连接池。Jedis对close方法进行了改造,如果是连接池中的连接对象,调用Close方法将会是把连接对象返回到对象池,若不是则关闭连接。以下为Jedis的close方法和JedisPool的getResource()方法的源码:

@Override
public void close() { //Jedis的close方法
    if (dataSource != null) {
        if (client.isBroken()) {
            this.dataSource.returnBrokenResource(this);
        } else {
            this.dataSource.returnResource(this);
        }
    } else {
        client.close();
    }
}

//另外从对象池中获取Jedis链接时,将会对dataSource进行设置
// JedisPool.getResource()方法
public Jedis getResource() {
    Jedis jedis = super.getResource();   
    jedis.setDataSource(this);
    return jedis;
}

通过Jedis实现Redis事务

Redis的事务相关知识参考[Redis基本事务操作]这篇文章

事务相关的命令有:MULTI、EXEC、DISCARD、WATCH、UNWATCH。

代码实现

public class TestRedisTX {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.15.133",6379);
        jedis.flushDB();

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello","world");
        jsonObject.put("name","oldou");

        //开启事务
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();

        //加乐观锁,对result进行监控
        jedis.watch(result);

		//有Redis的相关操作加锁,保证健壮性
        try {
            multi.set("user1",result);
            multi.set("user2",result);

            //代码抛出异常,事务执行失败
          //  int i = 1/0;

            multi.exec(); //成功则执行事务
        } catch (Exception e) {
      	    //如果事务执行失败就进行解锁
            //jedis.unwatch(); 
            multi.discard(); //失败则放弃事务
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();//关闭连接
        }
    }
}

输出:
在这里插入图片描述
代码中,通过jedis.multi();开启Redis的事务,jedis.watch(result);对result进行监控,接下来编写写命令入队列(multi.set("user1",result); multi.set("user2",result);),当执行multi.exec()时,Redis会执行队列中的命令,这个时候如果事务执行成功,就会finally中就会输出get到的值,如果事务执行失败,就会进行异常的捕获,同时将监控进行解锁caozuo jedis.unwatch();,并且放弃本次事务multi.discard(),最后不管事务执行是否成功,都要将Jedis进行关闭。

猜你喜欢

转载自blog.csdn.net/weixin_43246215/article/details/108067542