Redis客户端
1.前言
前面学习的Redis的基本操作和命令都是在redis命令行手动执行的,更多的时候,是使用redis的API来实现定制化的redis客户端操作redis服务器。接下来我们要了解Redis服务端和客户端的通信协议,以及Java语言的Redis客户端使用方法
Redis服务器在官网上公开了使用的协议RESP,任何一个第三方都可以通过上述协议,来实现一个和redis服务器通信的客户端程序
Java生态中,封装了RESP协议,实现的redis客户端有很多的,接下来我们使用的时Jedis
2.端口转发
这样的结构,就需要通过云服务器的外网IP来访问到Linux服务器。但是只修改外网IP是不够的,因为6379端口默认情况下是被服务器的防火墙给保护起来的,不能被外界访问(包括我们自己)
HajiHang的电脑就好比小区里的住宅楼,被NAT机制保护起来了,有人想偷东西,成本就会非常高,小偷得先想办法进入小区,然后再想办法进入单元楼,再想办法进HajiHang家;云服务器就是有外网IP的,云服务器就相当于暴露在大街上的门市房,有人相偷东西,成本就比较低了,只需要想办法进去即可,每给服务器开放一个端口,就好比开了一扇大门,开放的端口多了,门就多了,小偷进入的几率就更大了
那么就有人要说了直接在云服务器后台,把防火墙放开,不就行了嘛? ·不行!!!Redis的端口一旦公开到公网上,就特别容易被入侵!
那么就又有人要问了tomcat的端口号不也是公开到公网上的? ·虽然tomcat端口也开放了,但是tomcat的8080这个“锁”是不好撬开的,而Redis的6379这个“锁”就是很好撬开的!
还有人要问那我给redis换个端口是不是就安全了呢?? ·不安全,这种方式就相当于掩耳盗铃!
不能开放Redis端口号,我们又想要能够通过外网访问,有一下两种方式:
1.直接让Java程序也在Linux上运行
这就需要将代码打包成一个可执行的jar包,然后将jar包拷贝到Linux服务器上执行
2.配置ssh端口转发,把云服务器的Redis端口号,映射到本地主机上
ssh功能非常强大,其中非常重要的特性就是能够支持端口转发,想当于通过ssh的22端口,来传递其他端口的数据
本身我们就是通过Windows主机,访问云服务器的6379端口,于是构造一个特殊的ssh数据报就把要访问的redis请求,放到ssh数据包中
这个数据就会通过22端口号发送给服务器,服务器的ssh服务器程序就能够协议出上述的数据报,然后包数据报交给6379端口的程序
一个Linux主机上,存在的服务器有很多,ssh也可能需要来给多个端口传递数据,这个时候,为了区分不同的端口,往往会把服务器端口在本地用另一个端口进行表示
3.Java使用Redis步骤
3.1 导入依赖
Java操作Redis客户端有很多,其中最知名的是Jedis
创建maven项目,把Jedis的依赖拷贝到pom.xml中
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.0</version>
</dependency>
3.2 配置端口转发
Redis服务器安装在云服务器上,而我们编写的代码则是在本地主机,要想让本地主机能访问Redis,需要把Redis的端口通过云服务器后台页面的“防火墙/安全组”放开短空到公网上,但是这个操作非常危险(黑客很容易获取Redis中的内容)
因此我们可以通过端口转发方式,直接把服务器的Redis端口映射到本地
在Xshell中,进行如下配置:
1.右键服务器的会话,选择属性
2.找到隧道,配置转移规则
连接完成之后,就可以使用netstat命令查看本地这里的8888端口与有了没
当配置了端口转发之后,一定要断开之前的连接,重新连接才能生效
3.使用会话连接服务器
此时,访问本地8888就相当于访问对应服务器的6379,同时外面的客户端是无法直接访问云服务器的6379的
注意:Xshell和服务器必须处于连接状态,这样的映射才是有效的
3.3 连接Redis Server
使用JedisPool描述Redis服务器的位置,使用url表示
使用getResource和服务器建立连接
连接使用完毕需要close关闭,也可以直接使用try自动关闭
通过ping方法可以检测连接是否正确建立
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisDemo {
public static void main(String[] args) {
//后续如果我们的程序部署到云服务器此时就得按照云服务器的实际情况,来写ip和端口号
JedisPool jedisPool=new JedisPool("tcp://127.0.0.1:8888");
try(Jedis jedis=jedisPool.getResource()){
String ping=jedis.ping();
System.out.println(ping);
}
}
}
运行结果
注意:当前这个程序能跑通,除了配置ssh端口映射之外,还有一个要点,最开始安装Redis服务器的时候,要配置绑定的ip,以及关闭保护模式
通过cd /etc/redis ,以及vim redis.conf编辑Redis配置文件
这里默认绑定的ip是127.0.0.1此时只能本机和本机访问,不能跨主机访问
这里默认是yes,开启保护模式,跨主机也是不能访问的
4.基础操作
4.1 set和get
key不存在时,得到的value为null
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisDemo {
private static void testGetAndSet(Jedis jedis){
jedis.set("key1","value1");
jedis.set("key2","value2");
String value1=jedis.get("key1");
System.out.println(value1);
String value2=jedis.get("key2");
System.out.println(value2);
String value3=jedis.get("NoSuchKey");
System.out.println(value3);
}
public static void main(String[] args) {
//后续如果我们的程序部署到云服务器此时就得按照云服务器的实际情况,来写ip和端口号
JedisPool jedisPool=new JedisPool("tcp://127.0.0.1:8888");
try(Jedis jedis=jedisPool.getResource()){
testGetAndSet(jedis);
}
}
}
运行结果:
通过Xshell观察:
4.2 exists和del
del可以删除多个key,以及边长参数列表(要求边长参数必须是相同数据类型的,会代用类型检查),返回值是实际删除的key的个数
exists检测key是否存在,如果key存在返回true,如果key不存在则返回false
private static void testExistsAndDel(Jedis jedis){
//避免之前其他的操作产生的数据对本次操作产生影响
jedis.flushAll();
jedis.set("key1","value");
jedis.set("key2","value");
jedis.set("key3","value");
boolean ret=jedis.exists("key1");
System.out.println(ret);
long n=jedis.del("key1");
System.out.println(n);
n=jedis.del("key1","key2","key3");
System.out.println(n);
}
运行结果
4.3 keys
获取符合条件的key
private static void testKeys(Jedis jedis){
jedis.flushAll();
jedis.set("key1","value1");
jedis.set("key2","value2");
jedis.set("key3","value3");
jedis.set("key4","value4");
jedis.set("myKey","value5");
Set<String> set=jedis.keys("*");
System.out.println(set);
set=jedis.keys("key?");
System.out.println(set);
}
运行结果
4.4 expire和ttl
设置过期时间和获取剩余生存时间
private static void testExpireAndTtl(Jedis jedis) throws InterruptedException {
jedis.flushAll();
jedis.set("key1","value");
jedis.expire("key1",10);
long ttl= jedis.ttl("key1");
System.out.println(ttl);
Thread.sleep(8000);
ttl= jedis.ttl("key1");
System.out.println(ttl);
Thread.sleep(3000);
ttl= jedis.ttl("key1");
System.out.println(ttl);
}
运行结果:
4.5 type
打印key对应的value的类型
private static void testType(Jedis jedis){
jedis.set("key1","value1");
System.out.println(jedis.type("key1"));
jedis.lpush("key2","a","b","c");
System.out.println(jedis.type("key2"));
jedis.hset("key3","name","hajiHang");
System.out.println(jedis.type("key3"));
jedis.sadd("key4","111","222","333");
System.out.println(jedis.type("key4"));
jedis.zadd("key5",89,"lll");
System.out.println(jedis.type("key5"));
}
运行结果: