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
配置步骤
- 拷贝redis.conf文件
- 开启daemonize为yes
- 修改pid文件名
- 修改端口
- 修改log文件名
- 修改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
不同情景
一主多仆:
- Master shutdown后,Slave保持待命,且连接状态变为down
Master重启后,主从关系不变,Slave仍可正常工作 - 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]
哨兵模式
主从切换的自动版。能够后台监控主机是否故障,如果故障了可以通过投票数自动将备机转化为主机
- 新建sentinel.conf文件
- sentinel monitor [主机名随便取] [主机IP] [主机端口] 1(最后的1代表Slave票数多于1票即可转化为Master)
- 启动哨兵: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);
}
}