redis
1.jedis: redis的java客户端;
快速入门使用:
1.导入依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.9.0</version>
</dependency>
测试的话可以导入junit依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
2.使用:
@Test
public void testJedis(){
//注册jedis
//1.设置
jedis =new Jedis("localhost",6379);
//2.设置密码
// jedis.auth("******");
//3.选择库
jedis.select(0);
//开始使用
//1.存入数据
String result = jedis.set("name", "xiangxiang");
System.out.println(result);
//2.获取数据
String name = jedis.get("name");
System.out.println("name="+name);
//结束使用释放内存
if(jedis !=null){
jedis.close();
}
}
---------------------------------------
2.jedis连接池:
public class JedisConnectionFactory {
private static final JedisPool jedispool;
public static final int port=6379;
static {
//配置连接池
JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
//最大连接
jedisPoolConfig.setMaxTotal(8);
//最大空闲连接
jedisPoolConfig.setMaxIdle(8);
//最小空闲连接
jedisPoolConfig.setMinIdle(0);
//设置最长等待时间
jedisPoolConfig.setMaxWaitMillis(200);
jedispool=new JedisPool(jedisPoolConfig,"localhost",port,200);
}
//获取jedis对象
public static Jedis getJedis(){
return jedispool.getResource();
}
}
使用时直接调用方法即可: jedis = JedisConnectionFactory.getJedis();
--------------------------------------------------------
3,springdataredis:redis的java客户端
1.springboot项目导入依赖(也可以创建时在nosql中勾选,但是勾选后仍要导入连接池依赖) :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--连接池依赖-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2.配置文件配置相关配置
例如:
spring:
data:
redis:
host: "localhost"
port: 6379
password:
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 200
3.注入redisTemplate使用:
@Autowired
private RedisTemplate redisTemplate;
@Test
void testString() {
redisTemplate.opsForValue().set("name","xiangxiang");
System.out.println(redisTemplate.opsForValue().get("name"));
redisTemplate.opsForHash().put("user:1","name","haha");
redisTemplate.opsForHash().put("user:1","age","18");
redisTemplate.opsForHash().put("user:1","sex","woman");
System.out.println(redisTemplate.opsForHash().entries("user:1"));
}
由于序列化,更建议设置redistemplate序列化器:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
//创建redisTemplate对象
RedisTemplate<String,Object> template=new RedisTemplate<>();
//设置连接工厂
template.setConnectionFactory(redisConnectionFactory);
//创建JSON序列化工具
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//设置key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
//设置value的序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
//返回
return template;
}
}
使用时只要把private RedisTemplate redisTemplate;改为: private RedisTemplate<String,Object> redisTemplate;
------------
stringRedisTemplate: 可以代替redisTemplate;
优点:序列化key时不会转为"@class": "com.xiangxiang.pojo.Student" 的形式而是"@class": "Student" 可以节约内存;
缺点:写入时要手动把对象序列化转为JSON, 读取时也要手动把读取到的JSON反序列化为对象;
代码:
@Autowired
private StringRedisTemplate stringRedisTemplate;
//JSON工具
private static final ObjectMapper mapper=new ObjectMapper();
@Test
void testString() throws JsonProcessingException {
stringRedisTemplate.opsForValue().set("name","xiangxiang");
System.out.println(stringRedisTemplate.opsForValue().get("name"));
stringRedisTemplate.opsForHash().put("user:1","name","haha");
stringRedisTemplate.opsForHash().put("user:1","age","18");
stringRedisTemplate.opsForHash().put("user:1","sex","woman");
System.out.println(stringRedisTemplate.opsForHash().entries("user:1"));
Student s1=new Student("ZhangSan",18);
//对象转为json
String json = mapper.writeValueAsString(s1);
//写入数据
stringRedisTemplate.opsForValue().set("student1",json);
//读取数据
String val = stringRedisTemplate.opsForValue().get("student1");
//json转为对象
Student student = mapper.readValue(val, Student.class); //第二个参数时对象类型的字节码文件
System.out.println("student="+student);
}
注意点:对string类型操作时,操作一样,对对象类型操作时才与redisTemplate不同;
---------------------------------------------------
3.tostring()方法相当与new了一个新的字符串;如果用tostring().intern()就是先去串池里寻找,如果有就直接用,没有就new;
----------------------------------------------------------
4.UUID:
UUID 的全称是 通用唯一识别码。它是一个用于识别信息的128位的数字标识符。
它的核心特性体现在名字上:
1.通用: 可以在任何地方生成,不需要中心化的授权机构。
2.唯一: 在可预见的未来,在同一时空中的所有系统中,生成重复标识符的概率极低,几乎可以忽略不计。
-----------------------------------------------------------------
5.redisson;
------------------------------------------
6.分布式锁的原理(跳过,以后学习);
--------------------------------------
7.创建线程池和线程任务:
//创建线程池
private static final ExecutorService SECKILL_ORDER_EXECUTOR=Executors.newSingleThreadExecutor();
//创建线程任务
private class VoucherOrderHandler implements Runnable{
@Override
public void run() {
}
}
----------------------------------
8.redis的主从架构:
redis中从结构只有一个主节点,可以有多个从节点;
从节点需要执行slaveof命令来确定主节点;
从节点连接主节点的第一次需要做全量同步;
主从节点数据同步分为全量同步和增量同步;
全量同步有三个阶段:
1.从节点发送自己的replid 和 offset 给主节点来和主节点的 replid 来匹配,匹配成功说明不是第一次连接,不需要做全量同步只需要做增量同步,否则需要做全量同步; 如果是全量同步,主节点会返回自己的replid 和 offset给从节点,让从节点继承自己的replid;
2.主节点执行bgsave生成RDB操作,并且将未来得及存储在RDB中的命令存储到缓冲区repl_baklog中, 然后将RDB传给从节点,从节点执行brush指令,清空自身然后执行RDB文件;
3.主节点将缓存在repl_baklog中的数据发送给从节点,从节点执行剩下的命令实现数据同步;
增量同步两个阶段:
1.和全量同步第一阶段一样,replid匹配说明是做增量同步;
2.主节点将缓存在repl_baklog中的数据发送给从节点,从节点执行剩下的命令实现数据同步;
--------
repl_backlog相当于一个环形数组,可以覆盖原先传输给从节点的数据;但是如果从节点宕机,repl_backlog就会发生错误,覆盖未传输的数据,就要等从节点修复好执行全量同步;
--------
执行全量同步的两种情况:
1.第一次连接
2.从节点宕机导致repl_backlog覆盖未传输的数据;
--------
修正:
第一阶段从节点还会和prior_replid匹配,
如果 replid = 主节点当前 replid 且 offset 合法 → 执行增量同步
如果 replid = 主节点的 prior_replid (历史id)也可以尝试执行增量同步(PSYNC 2 特性)
否则才执行全量同步
第一次连接不一定增量同步,
如果主节点重启过,产生新的replid,
从节点有主节点的 旧 replid(主节点 prior_replid == 从节点 replid)
offset 仍然在 backlog 范围内
仍然可以增量同步!
---------------------------
哨兵集群依赖主从集群;
分片集群内含主从结构;
----------------------------------
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Hexo!