redis——学习笔记(下)

 一,Redis事务操作

 Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

特点:

  • Redis事务没有隔离级别的概念:批量操作在发送Exec命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的跟新,事务外查询不能看到。
  • Redis不保证原子性:Reids中,单条命令式原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍然会被执行。

multi             #开启事务

exec             #提交事务

Discard         #取消事务 

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 a1 
QUEUED
127.0.0.1:6379> set k2 a2 
QUEUED
127.0.0.1:6379> set k3 a3
QUEUED
127.0.0.1:6379> get k2 
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK
4) "a2"

 错误不影响其他结果

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1 
QUEUED
127.0.0.1:6379> set k1 2
QUEUED
127.0.0.1:6379> set k2 3
QUEUED
127.0.0.1:6379> set k4 2
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) OK
127.0.0.1:6379> 

二,Redis 乐观锁

乐观锁总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据

悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁

watch key         #监视字段,当字段数据发生变动,事务执行失败

在watch监视之后,在另一个redis窗口修改了money数据导致事务执行失败

127.0.0.1:6379> watch money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> decrby money 1000
QUEUED
127.0.0.1:6379> INCRby money 122
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

 失败后,通过unwatch释放锁,重新watch获取最新的值

127.0.0.1:6379> UNWATCH
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> decrby money 1000
QUEUED
127.0.0.1:6379> incrby money 122
QUEUED
127.0.0.1:6379> exec
1) (integer) 100
2) (integer) 222

 三,Jedis

jedis 是redis官方推荐的java连接开发工具!使用java来操作redis中间件。

jiedis:采用直连,多个线程操作的话,不安全,如果想要避免不安全,使用jedis pool 连接池!更像BIO模式

1.打开Windows本地redis-server

 2.下载maven依赖

  <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.6.3</version>
  </dependency>

3.

连接本地redis,auth连接密码

  Jedis jedis=new Jedis("127.0.0.1",6379);
    jedis.auth("ccd");

开启事务,把命令都写到事务中,如果发生异常取消事务。

   try {
            multi.set("name", "ccd");
            multi.sadd("fruit","banner","apple","watermelon");
            multi.exec();
        }catch (Exception e)
        {
         multi.discard();
        }
        System.out.printf( jedis.get("name"));
        System.out.printf("sadd:"+ jedis.smembers("fruit"));
    }

四, lettuce

1,配置

采用netty,实例可以在多个线程中共享,不存在线程不安全的情况,可以减少线程数据,更像NIO模式

        1).启动redis

        2).yml配置

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 1                #默认打开数据库

 jedis语法和redisTemplate https://www.cnblogs.com/z-sir/p/13664221.html 参考

2,序列化

自定义注解redisconfig


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class redisconfig {
    //自定义redisTemplate
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        //配置具体的序列化方式
        //json 序列化配置
        Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om=new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectJackson2JsonRedisSerializer.setObjectMapper(om);
        //String 的序列化
        StringRedisSerializer stringRedisSerializer= new StringRedisSerializer();
        //key 采用String 的序列化方式
        template.setKeySerializer(stringRedisSerializer);

        //hash的key 也采用string 的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);

        //value 序列化采用jackson
        template.setValueSerializer(stringRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

直接复制粘贴到自己的redisconfig

测试代码


import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class LettuceNewApplicationTests {
@Autowired
@Qualifier("redisTemplate")        //多个依赖,指定一个
    private RedisTemplate redisTemplate;
    @Test
    void contextLoads()  {
 User user=new User(1,"daads");
   redisTemplate.opsForValue().set("name",user);
   System.out.printf(""+ redisTemplate.opsForValue().get("name"));
    }

}

最后报错了

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `com.example.lettuce_new.User` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

内容已经set进去了但是无法使用get读取

最后在自己的实体类 写一个空的构造方法

最后输出

User{id=1, name='daads'}

redis中的内容

"[\"com.example.lettuce_new.User\",{\"name\":\"daads\",\"id\":1}]"

无乱码序列化成功

五,redis持久化操作

1.RDB

优势:

1). 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。

2). 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。

3). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。

4). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

缺点:

1)不能保证数据的精准性,系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

2)RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

配置:

 当key发生变化会保存

900秒内至少有一个key发生变化则dump内存快照

300秒内至少有10个key发生变化则dump内存快照

60秒内至少有1w个key发生变化则dump内存快照

在redis.confg中修改你保存文件的名称

dump快照 

保存机制:

 1)在满足规则的情况下,会自动保存

 2)在执行flushall命令时,会保存

 3)save命令可以保存

 4)shutdown命令可以选择保存不保存

恢复数据:只要将dump.rdb导入到redis文件夹中,redis-server启动时会自动恢复数据。

2,AOF

优势: 

(1)AOF可以更好的保护数据不丢失,一般AOF会以每隔1秒,通过后台的一个线程去执行一次fsync操作,如果redis挂掉了,最多丢失1秒的数据。

(2)AOF以append-only的模式写入,所以没有任何的磁盘寻址的开销,写入性能非常的高。

缺点:

(1)aof储存的是命令,对于一个100次的增加操作,rdb只储存结果,aof要储存100次的命令,所以内存占用高。

  (2)aof恢复数据比rdb慢。

配置:

appendonly 默认为no要在redis.conf中开启

appendfilename 生成aof的名称

默认为一秒执行一次

always 执行一个命令存储一次

everysec 一秒执行一次

no   由操作系统自动调度刷磁盘

 

 数据可视.且数据可以修改

 重启redis-server,进入cli报错

 使用redis-check-aof --fix  修复文件

再次重启server进入cli成功 。但是有一条数据被删除了

六,redis主从复制

是指将一台redis服务器的数据,复制到其他redis服务器。前者称为主节点,后者为从节点。

数据传递是单向的只能从主节点传到从节点。默认情况下都是主节点。

主从复制的作用主要包括:

1,数据冗余:主从复制实现了数据的热备份

2,负载均衡:主从复制的基础上,配合读写分离,可以由主节点实现写,从节点实现读,分担服务器负载,在写少读多的情况下可以大大提高redis的服务器并发量

3,故障恢复:当主节点宕机,可以直接使用从节点变成主机。手动配置或使用哨兵自动检查

[root@ccd redis-5.0.7]# redis-cli
127.0.0.1:6379> info replication     #查看主机
# Replication
role:master              #查看主从
connected_slaves:0            #没有从机
master_replid:2eba218c20027e0c88da76a6e19db823bdb13c93
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

从机 

127.0.0.1:6381> slaveof 127.0.0.1 6380     #配置他的主
OK
127.0.0.1:6381> info replication
# Replication
role:slave                   #变成从机
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:7f09953890e93c62d7811ea9989d7139030c35ba
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

主机

127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=696,lag=0        #从机数据
slave1:ip=127.0.0.1,port=6379,state=online,offset=696,lag=0
master_replid:7f09953890e93c62d7811ea9989d7139030c35ba
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:696
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:696

主从都有 

# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:59258  
slave_priority:100
slave_read_only:1
connected_slaves:1
slave0:ip=127.0.0.1,port=6379,state=online,offset=59258,lag=1         #从机
master_replid:7f09953890e93c62d7811ea9989d7139030c35ba                #主机
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:59258
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:59258

        主机宕机,让从机变成主机   

[root@ccd redis-5.0.7]# redis-cli -p 6380
127.0.0.1:6380> shutdown save
not connected> 
[root@ccd redis-5.0.7]# redis-cli -p 6381 slaveof no one   #指定从机变成主机
OK
[root@ccd redis-5.0.7]# redis-cli -p 6381
127.0.0.1:6381> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6379,state=online,offset=60084,lag=0
master_replid:27d1a1dd144d9f7e9e0255091aff4f223bba60cc
master_replid2:7f09953890e93c62d7811ea9989d7139030c35ba
master_repl_offset:60084
second_repl_offset:60057
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:60084
127.0.0.1:6381> 

此时宕机的主机恢复也没有从机

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值