redis-----java客户端
一、引入jedis依赖
Maven Repository: redis.clients » jedis
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>5.2.0</version></dependency>
二、关于开放redis端口的问题
java开发代码,高度依赖于Windows(IDEA)
我们Windows客户端想要访问redis服务器,就需要通过云服务器的外网IP来访问linux服务器,我们会想到修改外网IP,但是这是不够,redis的6379端口,默认是被云服务器的防火墙保护起来的,不能被外面访问,但是我们也访问不了,就可以在云服务器后台把防火墙6379端口放开,这样是不可以的,因为redis端口一旦公开在公网上,很容易被黑客攻击入侵
虽然tomcat端口也放开了,但是tomcat的端口是不容易被入侵的,但是redis的6379端口就很容易被入侵,所以我们想不开放redis端口,又想通过外网访问,我们就可以:
1. 把java程序放在linux上运行,把代码打成jar包,把jar包放到linux服务器上执行,手续比较繁琐
2. 配置ssh端口转发,把云服务器的redis端口,映射到本地主机
简单来说,ssh服务程序相当于一个送外卖的,Windows主机和linux服务器相当于商家和客户,通过外卖小哥(ssh)将对应单号(端口号)送到对应的用户手上
映射redis端口到本地
在本地的cmd输入netstat -ano | findstr 8888,看看端口转发是否配置成功
三、连接redis服务器
public class RedisDemo {public static void main(String[] args) {//连接redis服务器JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");//获取jedis对象try(Jedis jedis=jedisPool.getResource()){String ping = jedis.ping();System.out.println(ping);}}
}
代码中
try
的写法是 try-with-resources 语法,这是 Java 7 引入的一种异常处理机制,主要用于 自动释放资源,特别适合处理实现了AutoCloseable
接口的资源(如文件流、数据库连接、网络连接等)。具体分析这段代码:
java
运行
try(Jedis jedis = jedisPool.getResource()) {String ping = jedis.ping();System.out.println(ping); }
1. 语法特点:
- 在
try
关键字后的括号()
中声明资源(这里是Jedis
对象)。- 资源必须实现
AutoCloseable
接口(Jedis
间接实现了该接口)。- 代码块执行完毕后,无需手动调用
close()
方法,Java 会自动释放资源。2. 优势:
- 简化代码:避免了传统
try-finally
中手动关闭资源的繁琐(如jedis.close()
)。- 确保资源释放:即使代码块中发生异常,资源也能被可靠释放,防止资源泄露。
- 可读性更好:资源声明与释放逻辑分离,代码更清晰。
对比传统写法:
如果不用 try-with-resources,需要手动关闭资源:
Jedis jedis = null; try {jedis = jedisPool.getResource();String ping = jedis.ping();System.out.println(ping); } finally {if (jedis != null) {jedis.close(); // 手动关闭资源} }
显然,try-with-resources 写法更简洁且安全,因此在处理需要关闭的资源时(如 Redis 连接、数据库连接等)非常推荐使用。
JedisPool jedisPool = new JedisPool("tcp://127.0.0.1:8888");
这里的ip和端口号仅限于当前的开发阶段,后续如果我们的程序需要部署到与服务器上,就得按照与服务器的实际情况来写
文件在etc/redis/redis.conf
四、使用命令
1.通用命令
1.set,get
//清空数据库jedis.flushAll();//设置数据jedis.set("key","1111");//获取数据String val = jedis.get("key");System.out.println(val);System.out.println("----------------------");//设置数据超时时间jedis.setex("key1",1,"设置超时时间的1111");//获取数据String val1 = jedis.get("key1");System.out.println(val1);Thread.sleep(2000);//2秒后获取数据String val2 = jedis.get("key1");System.out.println(val2);System.out.println("----------------------");SetParams params=new SetParams();//设置超时时间params.ex(1);//不存在才能设置成功params.nx();//存在才能设置成功params.xx();jedis.set("key2","设置超时时间的2222",params);
2.exists,del
public static void test2(Jedis jedis){jedis.set("key","1111");jedis.set("key1","222");jedis.set("key2","333");jedis.set("key3","444");//判断key是否存在Boolean exists = jedis.exists("key");System.out.println(exists);//删除keyLong del = jedis.del("key");//判断key是否存在exists = jedis.exists("key");System.out.println(exists);System.out.println("----------------------");//删除多个数据Long del1 = jedis.del("key1", "key2", "key3");}
3.keys *
Set<String> keys = jedis.keys("*");
4.expire,ttl,type
public static void test1(Jedis jedis) throws InterruptedException {
jedis.set("key","1111");
//设置超时时间
jedis.expire("key",10);
Thread.sleep(2000);
//获取超时剩余时间System.out.println(jedis.ttl("key"));
//获取数据类型System.out.println(jedis.type("key"));Thread.sleep(9000);
//判断key是否存在boolean key = jedis.exists("key");System.out.println(key);System.out.println("----------------------");
//获取数据类型jedis.lpush("list","1111","2222","3333");System.out.println(jedis.type("list"));
}
2.String命令
1.mset,mget
public static void test3(Jedis jedis){jedis.mset("key1","1111","key2","2222","key3","3333");List<String> mget = jedis.mget("key1", "key2", "key3");System.out.println(mget);
}
mget中有几个key就返回几个元素,没有key就返回null
2.setrange,getrange
jedis.set("key1","abcdefgh");//截取字符串System.out.println(jedis.getrange("key1", 0, 2));//修改字符串jedis.setrange("key1", 2, "12");System.out.println(jedis.get("key1"));
3.append,incr,decr,incrBy,decrBy
jedis.set("key1","1111");//追加字符串jedis.append("key1","2222");System.out.println(jedis.get("key1"));System.out.println("----------------------");jedis.set("key2","100");//自增jedis.incr("key2");System.out.println(jedis.get("key2"));//自增指定值jedis.incrBy("key2",2);System.out.println(jedis.get("key2"));//自减jedis.decr("key2");System.out.println(jedis.get("key2"));//自减指定值jedis.decrBy("key2",2);System.out.println(jedis.get("key2"));
3.list命令
public static void test4(Jedis jedis){jedis.lpush("list","1111","2222","3333");//获取列表长度System.out.println(jedis.llen("list"));//获取列表数据List<String> list = jedis.lrange("list", 0, -1);System.out.println(list);//删除列表数据Long lrem = jedis.lrem("list", 1, "2222");System.out.println(lrem);//删除左元素String lpop = jedis.lpop("list");System.out.println(lpop);//删除右元素String rpop = jedis.rpop("list");System.out.println(rpop);//阻塞删除List<String> list1 = jedis.brpop(0, "list");System.out.println(list1);
}
4.set命令
public static void test5(Jedis jedis){jedis.sadd("set","1111","2222","3333");jedis.sadd("set2","1111","2222","4444","5555");//获取集合长度System.out.println(jedis.scard("set"));//获取集合数据Set<String> set = jedis.smembers("set");System.out.println(set);//判断元素是否存在Boolean sismember = jedis.sismember("set", "1111");System.out.println(sismember);//删除元素Long srem = jedis.srem("set", "1111");System.out.println(srem);//并集Set<String> union = jedis.sunion("set", "set2");System.out.println(union);//交集Set<String> intersect = jedis.sinter("set", "set2");System.out.println(intersect);//差集Set<String> diff = jedis.sdiff("set", "set2");System.out.println(diff);
}
5.hash命令
public static void test6(Jedis jedis){jedis.hset("hash","key1","1111");jedis.hset("hash","key2","2222");//获取hash长度System.out.println(jedis.hlen("hash"));//获取hash数据System.out.println(jedis.hgetAll("hash"));//获取hash指定key的值System.out.println(jedis.hget("hash","key1"));//判断hash指定key是否存在System.out.println(jedis.hexists("hash","key1"));//删除hash指定keySystem.out.println(jedis.hdel("hash","key1"));//获取hash所有keySystem.out.println(jedis.hkeys("hash"));//获取hash所有valueSystem.out.println(jedis.hvals("hash"));//设置多个hash值jedis.hmset("hash", Map.of("key3","3333","key4","4444"));//获取多个hash值System.out.println(jedis.hmget("hash","key3","key4"));
}
6.zset命令
public static void test7(Jedis jedis){jedis.zadd("zset",1,"1111");jedis.zadd("zset",2,"2222");jedis.zadd("zset",3,"3333");//获取有序集合长度System.out.println(jedis.zcard("zset"));//获取有序集合数据System.out.println(jedis.zrange("zset",0,-1));//获取有序集合指定分数区间的元素System.out.println(jedis.zrangeByScore("zset",0,2));//获取有序集合指定分数区间的元素个数System.out.println(jedis.zcount("zset",0,2));//删除有序集合指定元素System.out.println(jedis.zrem("zset","1111"));//获取有序集合指定元素的分数System.out.println(jedis.zscore("zset","2222"));//获取有序集合指定元素的排名System.out.println(jedis.zrank("zset","3333"));//获取有序集合指定元素的排名System.out.println(jedis.zrevrank("zset","3333"));
}
五、javaSpring客户端
1.创建项目引入redis依赖
配置ip地址和端口号
2.StringRedisTemplate
StringRedisTemplate
是 Spring Data Redis 框架中的一个类,用于在 Spring 应用程序中方便地操作 Redis 数据库,专门处理字符串类型的数据。以下是关于它的详细介绍:
继承关系和作用
StringRedisTemplate
继承自 RedisTemplate
,RedisTemplate
是 Spring 对 Redis 各种操作的通用封装,支持 Redis 所有数据结构的操作。而 StringRedisTemplate
是对 RedisTemplate
的一种特殊化,将键和值的序列化方式默认设置为字符串序列化,使得在处理字符串类型数据时更加便捷,无需额外配置序列化器 。
主要方法
- 存储数据
opsForValue().set(String key, String value)
:向 Redis 中以指定的key
存储对应的value
,例如stringRedisTemplate.opsForValue().set("username", "John");
,就将键为"username"
,值为"John"
的键值对存入 Redis 。opsForValue().set(String key, String value, long timeout, TimeUnit unit)
:除了设置键值对,还可以设置过期时间,如stringRedisTemplate.opsForValue().set("token", "abc123", 60, TimeUnit.MINUTES);
,表示"token"
这个键对应的值"abc123"
在 60 分钟后过期 。
- 获取数据
opsForValue().get(String key)
:根据指定的key
从 Redis 中获取对应的值,例如String name = stringRedisTemplate.opsForValue().get("username");
。
- 删除数据
delete(String key)
:根据key
删除 Redis 中对应的键值对,比如stringRedisTemplate.delete("token");
。
使用示例
在 Spring Boot 项目中,先确保引入了 Spring Data Redis 依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在控制器类或服务类中就可以通过依赖注入的方式使用 StringRedisTemplate
:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;@RestController
public class RedisController {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@GetMapping("/setData")public String setData() {stringRedisTemplate.opsForValue().set("message", "Hello Redis!", 10, TimeUnit.MINUTES);return "Data set successfully";}@GetMapping("/getData")public String getData() {return stringRedisTemplate.opsForValue().get("message");}
}
在上述示例中,通过两个接口分别演示了使用 StringRedisTemplate
向 Redis 存储带有过期时间的数据,以及从 Redis 中获取数据的操作。
3.使用String
@RequestMapping("/testString")@ResponseBodypublic String testString() {redisTemplate.opsForValue().set("key","value");redisTemplate.opsForValue().set("key2","value2");String s = redisTemplate.opsForValue().get("key");System.out.println(s);return "ok:"+s;}
4.使用list
@RequestMapping("/testList")@ResponseBodypublic String testList() {redisTemplate.opsForList().leftPush("list","value");redisTemplate.opsForList().leftPush("list","value2");String s = redisTemplate.opsForList().leftPop("list");System.out.println(s);return "ok:"+s;}
5.使用hash
@RequestMapping("/testHash")@ResponseBodypublic String testHash() {redisTemplate.opsForHash().put("hash","key","value");redisTemplate.opsForHash().put("hash","key2","value2");String s = (String) redisTemplate.opsForHash().get("hash","key");System.out.println(s);return "ok:"+s;}
6.使用set
@RequestMapping("/testSet")@ResponseBodypublic String testSet() {redisTemplate.opsForSet().add("set","value");redisTemplate.opsForSet().add("set","value2");String s = (String) redisTemplate.opsForSet().pop("set");System.out.println(s);return "ok:"+s;}
7.使用zset
@RequestMapping("/testZSet")@ResponseBodypublic String testZSet() {redisTemplate.opsForZSet().add("zset","value",1);redisTemplate.opsForZSet().add("zset","value2",2);redisTemplate.opsForZSet().count("zset",1,2);redisTemplate.opsForZSet().rank("zset","value");return "ok:"+redisTemplate.opsForZSet().count("zset",1,2);}
8.对于StringRedisTemplate没有封装的方法,怎么调用底层的redis方法
@RequestMapping("/test")@ResponseBodypublic String test() {redisTemplate.execute((RedisConnection connection) -> {connection.flushAll();return null;});
return "通过execute方法调用redis的api,也就是Jedis";}
通过 Spring Data Redis 提供的 RedisTemplate 来执行底层 Redis 命令,直接操作 Redis 连接对象(RedisConnection),这种方式可以访问一些高级或底层的 Redis 功能。