目录
1.基础事务2.Redis事务回滚
3.使用watch命令监控事务
4.流水线(pipelined)
5.发布订阅
6.超时命令
7.使用Lua语言
1.基础事务
Redis事务是使用MULTI-EXEC的命令组合,提供两个重要的保证:
- 事务是一个被隔离的操作,事务中的方法都会被Redis进行序列化并按顺序执行,事务在执行的过程中不会被其他客户端发生的命令所打断。
- 事务是一个原子性的操作,它要么全部执行,要么就什么都不执行。
在Redis中使用事务经历三个过程:
- 开启事务(multi)
- 命令进入队列
- 执行事务(exec)
其它Redis事务命令
- watch key1[key2…] : 监听某些键,当被监听的键在事务执行前被修改,则事务会被回滚
- discard:回滚事务(回滚进入队列的事务命令)
2.Redis事务回滚
在执行事务命令的时候,在命令入队的时候,Redis会检测事务的命令是否正确,如果不正确则会产生错误。无论之前还是之后的命令都会被事务所回滚。
当命令格式正确,而因为操作数据结构引起的错误,则该命令执行执行错误,而之前还是之后的命令都会被正常执行。
3.使用watch命令监控事务
在multi命令之前使用watch命令监控某些键值对;
当Redis使用exec命令执行事务的时候,它首先会先去比对被watch命令所监控的键值对,
如果没有发生变化,那么它会执行事务队列中的命令,提交事务;
如果发生变化,那么它不会执行任何事务中的命令,而去事务回滚。
过程如图:
Redis参考了多线程中使用的CAS(比较与交换,Compare And Swap)去执行的
Redis机制是不会产生ABA问题的
4.流水线(pipelined)
在Redis事务中提供了队列,这是一个可以批量执行任务的队列,性能比较高,但是使用multi…exec事务命令是有系统开销的,因为会检测对应的锁和序列化命令。
Redis流水线技术: 没有任何附加条件的场景下使用队列批量执行一系列命令,提高系统性能,是一种通信协议。
使用Spring操作Redis流水线
@Test
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);
// 使用Java8的Lambda表达式
SessionCallback sessionCallback = (SessionCallback) (RedisOperations ops) -> {
for (int i = 0; i < 10000; i++) {
int j = i + 1;
ops.boundValueOps("pipeline_key_" + j).set("pipeline_value_" + j);
ops.boundValueOps("pipeline_key_" + j).get();
}
return null;
};
long start = System.currentTimeMillis();
// 执行Redis的流水线命令
List resultList = redisTemplate.executePipelined(sessionCallback);
long end = System.currentTimeMillis();
System.out.println(end - start);
}
5.发布订阅
发布订阅首先要有消息源,也就是要有消息发出来,比如银行通知。订阅者可以接收消息进行处理
Redis中的命令:
# 客户端1订阅 chat监听渠道
SUBSCRIBE chat
# 客户端2向渠道chat发送命令
publish chat "let's go!!"
# 客户端1
"let's go!!"
6. 超时命令
Redis超时命令
命令 | 说明 |
persist key | 持久化key,取消超时时间 |
ttl key | 查看key的超时时间(-1代表没有超时, 如果key不存在或已超时则为-2) |
expire key seconds | 设置超时时间戳(秒) |
问题: 如果key超时了,Redis会回收key的存储空间吗?
答: 不会。Redis的key超时不会被其自动回收,它只会表示哪些键值对超时了。 好处是如果一个很大的键值对超时,比如一个列表或者哈希结构,存在数以百万个元素,要对其回收需要很长的时间。如果采用超时回收,则可能产生停顿。
Redis提供两种方式回收超时键值对:
- 定时回收:在确定的某个时间触发一段代码,回收超时的键值对
- 惰性回收:当一个超时的键,被再次用get命令访问时,将触发Redis将其从内存中清空
7.使用Lua语言
Redis支持两种方式运行脚本
- 直接输入一些Lua语言的程序代码(简单的脚本)
- 将Lua语言编程写文件
对于采用简单脚本,Redis支持缓存脚本,使用SHA-1算法对脚本进行签名,然后把SHA-1标识返回回来,只要通过这个标识运行就可以了。
执行Lua程序代码命令格式: eval lua-script key-num [key1 key2 key3 … ] [value1 value2 value3 …]
key-num:整数代表参数中有多少个key,如果没有参数,则写0
7.1 Redis缓存脚本命令:
7.2 执行Lua文件:
test.lua
redis.call('set', KEYS[1], ARGV[1])
redis.call('set', KEYS[2], ARGV[2])
local n1 = tonumber(redis.call('get', KEYS[1]))
local n2 = tonumber(redis.call('get', KEYS[2]))
if n1 > n2 then
return 1
end
if n1 == n2 then
return 0
end
if n1 < n2 then
return 2
end