文章目录
- 前言
- SSH端口转发
- Jedis的使用
- Redis 通用命令的使用
- Redis String 类型命令的使用
- Redis List 类型命令使用
- Redis Hash 类型命令的使用
- Redis Set 类型的使用
- Redis Zset 类型命令的使用
前言
前面我们学习 redis 的时候都是在 redis 的原生客户端上输入 redis 命令的,由于 Redis 服务器官网公开了使用的协议——RESP,所有任何一个第三方都可以通过 RESP 协议来实现出一个和 redis 服务器通信的客户端程序。同样我们的 Java 也是。
有很多大佬开发出了相关的库,我们可以直接使用,这样我们程序眼就不必过多关注 RESP 协议的细节了。在 Java 生态中,封装了 RESP 协议实现的客户端有很多,在这里我们介绍的是其中的一个 JEDIS。
SSH端口转发
平时我们使用 Java 开发的时候,往往使用的平台是 Windows,而 Redis 服务器往往是在 Linux 系统上的,所以我们 Windows 用户要想使用 Linux 系统,最简单的方法就是买一个 Linux 云服务器,然后通过第三方软件来远程连接我们的 Linux 云服务器,这个第三方软件通常使用 SSH 协议来连接我们的云服务器的,那么我们的 Java 程序如何访问到我们的云服务上面的 Redis 服务器呢?
很多人可能会说,云服务器不是使用的公网 IP 吗,只要知道我们云服务器的 IP 地址和 Redis 的端口号不就能访问到这台云服务器上面的 Redis 服务器了吗?想法是好的,但是实际上行不通,如果我们放开云服务器的 6379 Redis 服务器端口,这样我们是可以访问到这台云服务器上面的 Redis 服务器,但是可能不出三天,你的这台云服务器就会被黑客给入侵了。既然这样的话,那么我们前面在使用 Java 的 Spring 的时候,要想访问我们写的程序,那么就需要将 Java 程序部署到 Linux 服务器上才能使用,那么这不也开放了 8080 端口吗?那这为什么可以呢?这是因为 Java 使用的端口黑客要是想攻击,需要花费的成本就会很高,而我们的 Redis 服务器使用的端口黑客要是想攻击,成本就相对较低,那么如果我更换 Redis 服务器使用的端口是否能解决这个问题呢?答案是不能的,这样做就相当于只是更换了门的位置,但是门上面的锁没有更换,是一样的。
那么既然这样的话,是否就意味着我们的 Java 程序无法访问到云服务上面的 Redis 服务器吗?这也不是的,为了保证 Java 程序也能访问到云服务器上面的 Redis 服务,有两种解决方法:
- 当写完 Java 程序之后,将 Java 程序打成 jar 包,然后部署到云服务器上面,这样客户端和服务器端就在一个机器上了,这样就不容易产生安全问题了。这样虽然可以解决,但是比较麻烦。
- 配置 SSH 端口转发
SSH端口转发是一种通过SSH协议在本地和远程主机之间建立安全通道,实现端口之间的数据转发的技术。它允许用户在不直接访问目标主机的情况下,通过安全的SSH连接来访问该主机上的服务。SSH端口转发基于SSH协议的加密和身份验证机制,确保传输的数据安全可靠。
SSH端口转发有两种主要类型:本地端口转发和远程端口转发。本地端口转发将远程计算机上的服务转发到本地计算机,使得本地计算机能够通过SSH隧道访问远程计算机上的服务。而远程端口转发则将本地计算机上的服务转发到远程计算机,实现远程计算机对本地服务的访问。
我们这里使用的是将远程计算机上的服务转发到本地计算机:
我这里使用的是 xshell 来连接我的云服务器,在 xshell 中右击我们要使用的云服务器,然后选择属性:
选择隧道 -> 添加:
确定之后,重启我们的云服务器,并且如果需要使用远程计算机上的服务,需要保证我们的 xshell 和 云服务器是处于连接状态,我们可以在本地计算机上使用 netstat -ano | findstr 8888
来查看是否绑定成功。
如果没有绑定成功,或者 xshell 没有连接上云服务就查找不到这个端口。
不仅如此,为了能使我们的 Java 程序能成功访问到云服务器上的 Redis 服务,我们还需要设置 redis 的配置文件:
Jedis的使用
当完成 SSH 端口的映射之后,我们就可以说在 Java 程序中访问我们云服务器上的 Redis 服务器了。
首先因为 Jedis 属于第三方库,所以首先需要将 Jedis 的 maven 坐标导入到我们的项目中。
导入依赖之后,我们就可以使用 Jedis 了。
Redis 通用命令的使用
要想使用 Jedis,首先我们需要先得到一个类似 JedisPool 的池,然后再从这个 JedisPoll 中拿到 Jedis 对象:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisDemoGeneric {
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
try (Jedis jedis = jedisPool.getResource()) {
}
}
}
我们之所以选择 Jedis 作为 Java 的 Redis 客户端,是因为 Jedis 的方法和 Redis 的命令有极大的相似性,这样就降低了我们的学习成本。
test1();
public static void test1(Jedis jedis) {
jedis.flushAll(); //首先清空数据库,防止每次调用方法的时候,里面的数据造成影响
String pong = jedis.ping();
System.out.println(pong);
}
这里的红色不是报错,暂时先不用管。
public static void test1(Jedis jedis) {
jedis.flushAll(); //首先清空数据库,防止每次调用方法的时候,里面的数据造成影响
String pong = jedis.ping();
System.out.println(pong);
jedis.set("key","111");
String value = jedis.get("key");
System.out.println(value);
}
可以看到这里面有很多种方法:
如果我们在使用 set 方法的时候需要指定其他选项的时候,可以传入一个 SetParams 类型的参数:
public static void test1(Jedis jedis) {
SetParams setParams = new SetParams();
setParams.ex(30);
setParams.nx();
jedis.set("key1","111",setParams);
long time = jedis.ttl("key1");
System.out.println(time);
}
jedis.set("key","111");
boolean result = jedis.exists("key"); //判断key是否存在
System.out.println("result: " + result);
jedis.set("key","111");
jedis.set("key2","222");
long del = jedis.del("key"); //删除key
System.out.println("del: " +del);
boolean v1 = jedis.exists("key");
boolean v2 = jedis.exists("key2");
System.out.println("v1: " + v1);
System.out.println("v2: " + v2);
jedis.set("key1","111");
jedis.set("key2","222");
jedis.set("key3","333");
Set<String> keys = jedis.keys("*"); //对于keys命令的返回值,需要使用set类型来接收,因为redis中key是不可以重复的
System.out.println("keys: " + keys);
jedis.set("key1","111");
String type = jedis.type("key1");
System.out.println("type: " + type);
jedis.lpush("key2","111","222");
type = jedis.type("key2");
System.out.println("type: " + type);
jedis.hset("key3","f1","111");
type = jedis.type("key3");
System.out.println("type: " + type);
jedis.sadd("key4","111","222");
type = jedis.type("key4");
System.out.println("type: " + type);
jedis.zadd("key5",90.5,"111");
type = jedis.type("key5");
System.out.println("type: " + type);
Redis String 类型命令的使用
public static void test2(Jedis jedis) {
jedis.flushAll();
jedis.mset("key1","111","key2","222","key3","333");
List<String> list = jedis.mget("key1","key2","key3");
System.out.println("list: " + list);
}
jedis.set("key1","abcdefg");
String v = jedis.get("key1");
System.out.println("v: " + v);
jedis.setrange("key1",2,"xyz");
v = jedis.getrange("key1",0,-1);
System.out.println("v: " + v);
jedis.set("key1","abcdefg");
String v = jedis.get("key1");
System.out.println("v: " + v);
jedis.append("key1","xyz");
v = jedis.get("key1");
System.out.println("v: " + v);
jedis.set("key1","10");
String v = jedis.get("key1");
System.out.println("v: " + v);
long result = jedis.incr("key1");
System.out.println("result: " + result);
result = jedis.decr("key1");
System.out.println("result: " + result);
result = jedis.incrBy("key1",10);
System.out.println("result: " + result);
result = jedis.decrBy("key1",20);
System.out.println("result: " + result);
double d = jedis.incrByFloat("key1",13.14);
System.out.println("d: " + d);
Redis List 类型命令使用
jedis.flushAll();
jedis.lpush("key1","111","222","333"); //头插
List<String> list = jedis.lrange("key1",0,-1);
System.out.println("list: " + list);
jedis.rpush("key1","111","222","333");
List<String> list = jedis.lrange("key1",0,-1);
System.out.println("list: " + list);
String pop = jedis.lpop("key1");
System.out.println("lpop: " + pop);
pop = jedis.rpop("key1");
System.out.println("rpop: " + pop);
List<String> list = jedis.lrange("key1",0,-1);
System.out.println("list: " + list);
list = jedis.blpop(300,"key1","key2");
System.out.println("list: " + list);
Redis Hash 类型命令的使用
jedis.flushAll();
//hset可以一次只设置一对file-value
jedis.hset("key1","f1","111");
String v = jedis.hget("key1","f1");
System.out.println("v: " + v);
//hset也可通过map来一次设置多对file-set
Map<String,String> map = new HashMap<>();
map.put("f1","111");
map.put("f2","222");
jedis.hset("key2",map);
v = jedis.hget("key2","f2");
System.out.println("v: " + v);
jedis.hset("key1","f1","111");
boolean b = jedis.hexists("key1","f1");
System.out.println("b: " + b);
b = jedis.hexists("key1","key2");
System.out.println("b: " + b);
jedis.hset("key1","f1","111");
jedis.hdel("key1","f1");
String s = jedis.hget("key1","f1");
System.out.println("s: " + s);
Map<String,String> map = new HashMap<>();
map.put("f1","111");
map.put("f2","222");
map.put("f3","333");
map.put("f4","444");
jedis.hset("key1",map);
Set<String> set = jedis.hkeys("key1");
System.out.println("keys: " + set);
List<String> list = jedis.hvals("key1");
System.out.println("values: " + list);
Map<String,String> map = new HashMap<>();
map.put("f1","111");
map.put("f2","222");
map.put("f3","333");
map.put("f4","444");
jedis.hmset("key1",map);
List<String> list = jedis.hmget("key1","f1","f2","f4");
System.out.println("list: " + list);
Redis Set 类型的使用
jedis.flushAll();
jedis.sadd("key1","111","222","444","333");
Set<String> set = jedis.smembers("key1");
System.out.println("members: " + set);
jedis.sadd("key1","111","222","444","333");
Set<String> set = jedis.smembers("key1");
boolean b = jedis.sismember("key1","111");
System.out.println("b: " + b);
b = jedis.sismember("key1","10101010");
System.out.println("b: " + b);
jedis.sadd("key1","111","222","444","333");
long len = jedis.scard("key1");
System.out.println("len: " + len);
jedis.sadd("key1","111","222","444","333");
String pop = jedis.spop("key1");
System.out.println("pop: " + pop);
pop = jedis.spop("key1");
System.out.println("pop: " + pop);
pop = jedis.spop("key1");
System.out.println("pop: " + pop);
pop = jedis.spop("key1");
System.out.println("pop: " + pop);
pop = jedis.spop("key1");
System.out.println("pop: " + pop);
jedis.sadd("key1","111","222","444","333");
jedis.sadd("key2","111","222","777","888");
Set<String> set = jedis.sinter("key1","key2");
System.out.println("inter: " + set);
jedis.sadd("key1","111","222","444","333");
jedis.sadd("key2","111","222","777","888");
long len = jedis.sinterstore("key3","key1","key2");
System.out.println("len: " + len);
Set<String> set = jedis.smembers("key3");
System.out.println("set: " + set);
Redis Zset 类型命令的使用
jedis.zadd("key1",93.5,"zhangsan");
List<String> list = jedis.zrange("key1",0,-1);
System.out.println("set: " + list);
List<Tuple> tuple = jedis.zrangeWithScores("key1",0,-1);
System.out.println("tuple: " + tuple);
Map<String,Double> map = new HashMap<>();
map.put("zhangsan",93.0);
map.put("lisi",95.5);
map.put("wangwu",100.0);
jedis.zadd("key1",map);
List<String> list = jedis.zrange("key1",0,-1);
System.out.println("list: " + list);
List<Tuple> tuple = jedis.zrangeWithScores("key1",0,-1);
System.out.println("tuple: " + tuple);
Map<String,Double> map = new HashMap<>();
map.put("zhangsan",93.0);
map.put("lisi",95.5);
map.put("wangwu",100.0);
jedis.zadd("key1",map);
long len = jedis.zcard("key1");
System.out.println("len: " + len);
Map<String,Double> map = new HashMap<>();
map.put("zhangsan",93.0);
map.put("lisi",95.5);
map.put("wangwu",100.0);
jedis.zadd("key1",map);
long count = jedis.zrem("key1","zhangsan","lisi");
System.out.println("count: " + count);
List<Tuple> tuple = jedis.zrangeWithScores("key1",0,-1);
System.out.println("tuple: " + tuple);
Map<String,Double> map = new HashMap<>();
map.put("zhangsan",93.0);
map.put("lisi",95.5);
map.put("wangwu",100.0);
jedis.zadd("key1",map);
Double score = jedis.zscore("key1","zhangsan"); //这里尽量使用包装类,因为如果要获取的分数的元素不在zset中就会返回null,而普通类型double无法接收null
System.out.println("score: " + score);
score = jedis.zscore("key1","zhaoliu");
System.out.println("score: " + score);
Map<String,Double> map = new HashMap<>();
map.put("zhangsan",93.0);
map.put("lisi",95.5);
map.put("wangwu",100.0);
jedis.zadd("key1",map);
Long rank = jedis.zrank("key1","zhangsan"); //这里同样使用包装类
System.out.println("rank: " + rank);
rank = jedis.zrank("key1","lisi");
System.out.println("rank: " + rank);
rank = jedis.zrank("key1","wangwu");
System.out.println("rank: " + rank);
rank = jedis.zrank("key1","zhaoliu");
System.out.println("rank: " + rank);
如果我们使用 jedis 的时候遇到了问题,可以去 GitHub 上 jedis 的官方文档去看看。https://github.com/redis/jedis