简单记录,以下操作均已在IDEA中手动敲了一边。。。
1、Java操作Redis
创建maven项目,引入jedis依赖,把junit也引一下
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- <scope>test</scope>-->
基本操作,连接redis服务、选择库等:
package com.jin.test;
import redis.clients.jedis.Jedis;
import java.util.Set;
/**
* @author jinyunlong
* @date 2021/10/26 9:13
* @profession ICBC锅炉房保安
*/
//测试redis连接
public class TestRedis {
public static void main(String[] args) {
//创建jedis客户端对象
Jedis jedis = new Jedis("192.168.6.138",7000);
//选择使用一个库 默认:使用 0号库
jedis.select(0);
//获取redis中所有key信息
Set<String> keys = jedis.keys("*");
keys.forEach(key -> System.out.println("key = " + key));
//操作库相关
jedis.flushDB(); //清空当前库
jedis.flushAll(); //清空所有库
//释放资源
jedis.close();
}
}
操作key相关的一些api:
package com.jin.test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
/**
* @author jinyunlong
* @date 2021/10/26 9:30
* @profession ICBC锅炉房保安
*/
public class TestKey {
private Jedis jedis;
@Before
public void before(){
this.jedis = new Jedis("192.168.6.138",7000);
}
@After
public void after(){
jedis.close();
}
//测试key相关
@Test
public void testKey(){
//删除一个key
// jedis.del("name");
//删除多个key
// jedis.del("name","age");
//判断一个key是否存在exists
Boolean aBoolean = new Boolean(jedis.exists("name"));
System.out.println(aBoolean);
//设置一个key超时时间 expire pexpire
// Long age = jedis.expire("age", 100);
// System.out.println(age);
//查看一个key超时时间 ttl
Long ttl = jedis.ttl("age");
System.out.println(ttl);
//随机获取一个key
String s = jedis.randomKey();
System.out.println(s);
//修改key名称
// String rename = jedis.rename("hhhh","aaaa");
// System.out.println(rename);
//查看key对应值的类型
String name = jedis.type("age");
System.out.println(name);
}
}
操作String型的相关api:
package com.jin.test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.List;
/**
* @author jinyunlong
* @date 2021/10/26 9:30
* @profession ICBC锅炉房保安
*/
public class TestString {
private Jedis jedis;
@Before
public void before(){
this.jedis = new Jedis("192.168.6.138",7000);
}
@After
public void after(){
jedis.close();
}
//测试String相关
@Test
public void testString() {
//set
jedis.set("name","小金");
//get
String name = jedis.get("name");
System.out.println(name);
//mset
jedis.mset("content","割让大苏打","address","大型");
//mget
List<String> mget = jedis.mget("name", "content", "address");
mget.forEach(v -> System.out.println("v = " + v));
//getset 拿原始值再设置新值
String set = jedis.getSet("name", "小明");
System.out.println(set);
Long strlen = jedis.strlen("content");
System.out.println(strlen);
}
}
操作List型的相关api:
package com.jin.test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.List;
/**
* @author jinyunlong
* @date 2021/10/26 9:30
* @profession ICBC锅炉房保安
*/
public class TestList {
private Jedis jedis;
@Before
public void before(){
this.jedis = new Jedis("192.168.6.138",7000);
}
@After
public void after(){
jedis.close();
}
//测试List相关
@Test
public void testList() {
//lpush
jedis.lpush("names1","张三","李四","王五");
//rpush
jedis.rpush("names1","kkk","aaa","www");
//lrange
List<String> names = jedis.lrange("names1", 0, -1);
names.forEach(list -> System.out.println("list = " + list));
//lpop rpop
String names1 = jedis.lpop("names1");
System.out.println(names1);
//llen
Long names11 = jedis.llen("names1");
System.out.println(names11);
//etc、、、
}
}
由此看出,关于key、string、list,还有set、zset、hash型的数据操作,都被jedis封装成api了,只需要直接调用方法就行了。set、zset、hash的操作就不贴了,调用的方法名和客户端操作指令基本是一样的。
2、SpringBoot整合Redis
注意:具体使用哪个类要看业务场景需要使用的数据类型,建议使用RedisTemplate然后自定义key、value的数据类型,一般key为String,value为Object。注意使用RedisTemplate的话,对象必须实现对象序列化接口。
引依赖,写配置:
<!--引入依赖 spring data redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
server.port=8989
# redis
spring.redis.host=192.168.6.138
spring.redis.port=7000
spring.redis.database=0
使用StringRedisTemplate和RedisTemplate
package com.jin.redis;
import com.jin.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author jinyunlong
* @date 2021/10/26 11:15
* @profession ICBC锅炉房保安
*/
//启动springboot应用
@SpringBootTest(classes = SpringBootRedisApplication.class)
@RunWith(SpringRunner.class)
public class TestStringRedisTemplate {
//注入StringRedisTemplate
@Autowired
private StringRedisTemplate stringRedisTemplate; //key value 都是字符串
//操作redis中key相关
@Test
public void testKey(){
stringRedisTemplate.type("name"); //判断key对应值的类型
Set<String> keys = stringRedisTemplate.keys("*");//获取redis中所有key
keys.forEach(key -> System.out.println("key = " + key));
stringRedisTemplate.delete("name"); //删除一个key
Boolean name = stringRedisTemplate.hasKey("name"); //判断某个key是否存在
System.out.println(name);
Long name1 = stringRedisTemplate.getExpire("name"); //获取key超时时间 -1 永不超时 -2 key不存在 >=0 过期时间
System.out.println(name1);
stringRedisTemplate.randomKey(); //在redis中随机获取一个key
// stringRedisTemplate.rename("age","age1"); //修改key名字 判断key是否存在
stringRedisTemplate.move("age1",1);
//etc、、、
}
//操作redis中String字符串 opsForValue 实际操作就是redis中String类型
@Test
public void testString(){
stringRedisTemplate.opsForValue().set("name","小豆"); //set 用来设置一个key value
stringRedisTemplate.opsForValue().set("sqsqs","小grg豆");
stringRedisTemplate.opsForValue().set("dgd","sasa");
String value = stringRedisTemplate.opsForValue().get("name"); //用来获取key对应的value
System.out.println(value);
stringRedisTemplate.opsForValue().set("code","2357",120, TimeUnit.SECONDS); //设置一个key超时时间
stringRedisTemplate.opsForValue().append("name","好人");
}
//操作redis中List类型 opsForList 实际操作就是redis中list类型
@Test
public void testList(){
stringRedisTemplate.opsForList().leftPush("lll","dsds"); //创建一个列表 并放入一个元素
stringRedisTemplate.opsForList().leftPushAll("klklkl","Dsdsf","fgfhf","dwetet"); //创建一个列表 放入多个元素
List<String> objects = new ArrayList<>();
objects.add("vcvcv");
objects.add("nbnbnb");
stringRedisTemplate.opsForList().leftPushAll("objects",objects); //创建一个
List<String> range = stringRedisTemplate.opsForList().range("objects",0,-1); //遍历list
range.forEach(value -> System.out.println("value = " + value));
}
//操作redis中Set类型 opsForSet 实际操作就是redis中set类型
@Test
public void testSet(){
stringRedisTemplate.opsForSet().add("sets","dsds","gfgf","klkl","wewe"); //创建set 并放入多个元素
Set<String> sets = stringRedisTemplate.opsForSet().members("sets"); //查看set中成员
sets.forEach(set -> System.out.println("set = " + set));
Long sets1 = stringRedisTemplate.opsForSet().size("sets");
System.out.println(sets1);
}
//操作redis中Zset类型 opsForZset 实际操作就是redis中zset类型
@Test
public void testZSet(){
stringRedisTemplate.opsForZSet().add("zsets","dsds",200); //创建并放入元素
Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);//指定范围查询
zsets.forEach(value -> System.out.println(value));
}
//操作redis中Hash类型 opsForHash 实际操作就是redis中hash类型
@Test
public void testHash(){
stringRedisTemplate.opsForHash().put("maps","name","张三"); //创建一个hash类型 并放入key value
String o = (String) stringRedisTemplate.opsForHash().get("maps", "name");//获取hash中某个key值
Map<String,String> map = new HashMap<String,String>();
map.put("age","12");
map.put("bir","2012-12-12");
stringRedisTemplate.opsForHash().putAll("maps",map); //放入多个key value
List<Object> objects = stringRedisTemplate.opsForHash().multiGet("maps", Arrays.asList("name", "age"));
objects.forEach(object -> System.out.println(object));
List<Object> maps = stringRedisTemplate.opsForHash().values("maps");//获取所有values
Set<Object> maps1 = stringRedisTemplate.opsForHash().keys("maps");//获取所有keys
Long size = stringRedisTemplate.opsForHash().size("maps");
System.out.println("size = " + size);
}
//注入RedisTemplate key Object Value Object ===> 对象序列化 name new User() ===> name序列化 对象序列化
@Autowired
private RedisTemplate redisTemplate;
//opsForXXX Value String List Set Zset Hash
@Test
public void testRedisTemplate(){
/**
* redisTemplate对象中 key 和 value 的序列化都是 JdkSerializationRedisSerializer
* key: string
* value: object
* 修改默认key序列化方案 key StringRedisSerializer
*/
User user = new User();
//修改key序列化方案 String类型序列(一般常用key是string value是object的模式)
redisTemplate.setKeySerializer(new StringRedisSerializer());
// redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
user.setId(UUID.randomUUID().toString()).setName("fsdom").setAge(22).setBir(new Date());
redisTemplate.opsForValue().set("user",user); //redis进行设置 对象需要经过序列化
User user1 = (User) redisTemplate.opsForValue().get("user");
System.out.println(user1);
redisTemplate.opsForList().leftPush("list",user);
}
}
和jedis的api调用大同小异,只不过redisTemplate(StringReidsTemplate)多了一个.opsForXXX(具体要操作的类型)的调用,后面再去跟具体实现的方法。
spring data 为了方便我们对redis进行更友好的操作 因此又提供了bound api 简化操作,这个api的作用是对字符串类型key进行绑定,后续所有操作都是基于这个key操作,绑定list、set等的key有不同的bound方法:
package com.jin.redis;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* @author jinyunlong
* @date 2021/10/26 16:30
* @profession ICBC锅炉房保安
*/
@SpringBootTest(classes = SpringBootRedisApplication.class)
@RunWith(SpringRunner.class)
public class TestBoundAPI {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
//spring data 为了方便我们对redis进行更友好的操 因此又提供了bound api 简化操作
@Test
public void testBound(){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
//redisTemplate stringRedisTemplate 将一个key的多次操作进行绑定
stringRedisTemplate.opsForValue().set("name","zhangsan");
stringRedisTemplate.opsForValue().append("name","是一个好人");
String name = stringRedisTemplate.opsForValue().get("name");
System.out.println(name);
//对字符串类型key进行绑定,后续所有操作都是基于这个key操作
BoundValueOperations<String, String> name1 = stringRedisTemplate.boundValueOps("name");
name1.set("zhangsan");
name1.append("是一个好人");
String s = name1.get();
System.out.println(s);
//对 list set zset hash
BoundListOperations<String, String> lists = stringRedisTemplate.boundListOps("lists");
lists.leftPushAll("zhangsan","lisi","wangwu");
List<String> range = lists.range(0, -1);
range.forEach(list -> System.out.println(list));
//set
// stringRedisTemplate.boundSetOps();
// redisTemplate.boundSetOps();
//zset
// stringRedisTemplate.boundZSetOps();
// redisTemplate.boundZSetOps();
//hash
// stringRedisTemplate.boundHashOps();
// stringRedisTemplate.boundHashOps();
/**
* 1.针对于日后处理key value 都是String 使用StringRedisTemplate
* 2.针对于日后处理key value 存在对象 使用RedisTemplate(可以自定义把key(或者value)换成String,
* 使用redisTemplate.setKeySerializer(new StringRedisSerializer());)
* 3.针对于同一个key多次操作可以使用boundXXXOps() Value List Set Zset Hash的api简化书写
*/
}
}
3、Redis的应用场景例
redis应用场景
1.利用redis 中字符串类型完成 项目中手机验证码存储的实现
2.利用redis 中字符串类型完成 具有时效性业务功能 12306 淘宝 订单还有:40分钟
3.利用redis 分布式集群系统中 Session共享 memcache 内存 数据存储上限 数据类型比较简单 redis 内存 数据上限 数据类型单一问题
4.利用redis zset类型 可排序set类型 元素 分数 排行榜之类功能 销量排行 sales(zset) [商品id,商品销量]......
5.利用redis 分布式缓存 实现
6.利用redis 存储认证之后token信息 微信小程序 微信公众号 |用户 openid --->令牌(token) redis 超时
7.利用redis 解决分布式集群系统中分布式锁问题 redis 单进程 单线程 n 20 定义
jvm 1进程开启多个线程 synchronize int n=20
jvm 1进程开启多个线程 synchronize int n=20
...... LUA脚本
etc、其他杂项
redis后面其实还有缓存、主从复制、哨兵机制、集群、分布式session啥的要记,其实要单开一篇来记篇幅可能都不够,但是本人比较懒,这些就都没实践,也不难就简单贴几张概念图吧:
做缓存的话一般是给数据持久层做缓存,减轻数据库压力,提升查询效率:
缓存击穿:说白了就是缓存没被用上。 缓存雪崩:说白了就是缓存挂了。
主从复制:一主多备做备份,但是主如果挂了,剩下的备也不会变成主。引入哨兵机制实现主挂后,备->主。
简单的说哨兵就是带有自动故障转移功能的主从架构
无法解决: 1.单节点并发压力问题 2.单节点内存和磁盘物理上限
集群:解决了哨兵的两点问题,其具有高可用 、可扩展性 、分布式 、容错。
参考该文章:一文读懂Redis的四种模式,单机、主从、哨兵、集群
分布式session的管理:本质也是一对多的存储关系。
Redis使用场景的参考文章: Redis读书笔记(一)Redis可以做什么
未来学习计划
Redis的概念、安装、数据操作、与java的集成、应用场景用了三篇文章简单记了一下。马上就要11月份了,再学习下ES,现在日常开发的几个主流中间件就学习复习的差不多了(仅限于会用,实际业务场景来了可能自己都反应不过来这些东西是否应该用)。然后再学学spring5的一些技术点、JVM,最后再实战开发一个某粒商城;可能还不知道要到明年几月份才能学完呢。
道阻且长,继续努力吧😄