Redis学习笔记(3)

Redis事务

对于一组命令,按顺序地串行化执行而不会被其他命令插入,不允许加塞

主要命令:MULTI、EXEC、DISCARD、WATCH、UNWATCH

  • 正常执行:MULTI [指令集] EXEC
  • 放弃事务:MULTI [指令集] DISCARD
  • 当一系列指令中有某条指令有编译错误(例如无法识别的命令)时,整个事务中所有指令都无法执行
  • 当一系列指令中有某条指令有运行错误(例如对字符串采取自增操作)时,事务中只有该指令无法执行

因此可以说,Redis对事务是部分支持的

没有隔离级别的概念,不保证原子性

WATCH监控

WATCH [key] MULTI [指令集] EXEC

WATCH key[key1 key2 ...]

监视一个或多个key,如果在事务执行前这些key的值被其他命令更改,那么这个事务将被放弃

可以通过UNWATCH取消对所有key的监控后再重新WATCH

Redis的发布和订阅

是进程间的一种消息通信模式:pub发送消息,sub接收消息

先订阅后发布:

SUBSCRIBE c1 c2 s*(可使用通配符*)

PUBLISH c2 hello

PUBLISH s1 pattern-hello

Redis的复制

即主从复制,主机(Master)数据更新后根据既定策略同步数据到备机(Slave),Master主写,Slave主读

作用:读写分离、容灾

从库配置:SLAVEOF 主机IP 主机port

配置步骤

  1. 拷贝redis.conf文件
  2. 开启daemonize为yes
  3. 修改pid文件名
  4. 修改端口
  5. 修改log文件名
  6. 修改dump.rdb文件名

开启服务后:

​ 使用 info replication 查看主从复制信息

​ Slave连接主机,如:SLAVEOF 127.0.0.1 6379

Slave覆写Master已有的key时:

(error)READONLY You can't write against a read only slave

不同情景

一主多仆:

  1. Master shutdown后,Slave保持待命,且连接状态变为down
    Master重启后,主从关系不变,Slave仍可正常工作
  2. Slave shutdown之后,其他Slave正常工作
    Slave重启后,身份变化为Master,需要重新与原Master连接
    重连后shutdown过程中Master写入的数据在Slave中仍可正常访问

接力传递:

某一台机器既作为Slave又作为Master,该机器调用info replication指令显示的role仍然为Slave

主从切换:

Slave1成为新主机:SLAVEOF no one

Slave2连接新主机:SLAVEOF [Slave1.IP] [Slave1.port]

哨兵模式

主从切换的自动版。能够后台监控主机是否故障,如果故障了可以通过投票数自动将备机转化为主机

  1. 新建sentinel.conf文件
  2. sentinel monitor [主机名随便取] [主机IP] [主机端口] 1(最后的1代表Slave票数多于1票即可转化为Master)
  3. 启动哨兵:redis-sentinel redis/sentinel.conf

主机挂掉之后,某个Slave成为主机,其他Slave调整跟随对象。原主机重启后成为Slave

Jedis

Jedis初始化

Jedis jedis = new Jedis("127.0.0.1", 6379);
System.out.println(redis.ping());

Jedis事务

Transaction transaction = jedis.multi();
transaction.set("k1", "v1");
transaction.set("k2", "v2");
transaction.exec();
// transaction.discard();

watch过程中key的值被其他线程修改时,transaction.exec()会返回null,可通过这一点判断事务是否成功执行

// ...
jedis.watch("k1");
if (condition == false){
    jedis.unwatch();
    return false;
}else {
    Transaction transaction = jedis.multi();
    // ...
    return transaction.exec() != null;
}

主从复制

Jedis master = new Jedis("127.0.0.1", 6379);
Jedis slave = new Jedis("127.0.0.1", 6380);
slave.slaveof("127.0.0.1", 6379);
master.set("key", "读写分离");
// 由于内存读写极快,这里slave马上get可能会获得空值或旧值
System.out.println(slave.get("key"));

Jedis Pool

使用单例模式返回Jedis池的唯一实例

// ···单例模式返回
public static JedisPool getJedisPoolInstance{
    if(...){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(32);
        poolConfig.setMaxWaitMillis(60 * 1000);
        // 池配置...
        jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
    }
    return jedisPool;
}

// 释放
public static void release(JedisPool jedisPool, Jedis jedis){
    if(jedis != null){
        jedisPool.returnResourceObject(jedis);
    }
}

原文地址:https://www.cnblogs.com/2511zzZ/p/13080268.html