事务处理
redis事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制, 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后, 才会继续处理其他客户端的其他命令。 Redis中的事务是可以视为一个队列,即我们可以通过MULTI开始一个事务,这相当于我们声明了一个命令队列。 接下来,我们向Redis中提交的每条命令,都会被排入这个命令队列。 当我们输入EXEC命令时,将触发当前事务,这相当于我们从命令队列中取出命令并执行,所以Redis中一个事务从开始到执行会经历 开始事务 、 命令入队 和 执行事务 三个阶段。 ?
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name "walker"
QUEUED
127.0.0.1:6379> sadd list 1 2 3 4 5
QUEUED
127.0.0.1:6379> get name
QUEUED
127.0.0.1:6379> exec
1) OK
2) (integer) 5
3) "walker"
?
- 事务是由一系列操作组成的单个逻辑工作执行单元。特别地,因为在Redis中命令是存储在一个队列中,所以,事务中的所有命令都会按顺序执行,并且在执行事务的过程中不会被客户端发送的其它命令中断。
- 事务是一个原子操作,事物中的命令只有两种执行结果,即全部执行或者全部不执行。如果客户端在使用MULTI命令开启事务后因为意外而没有执行EXEC命令,则事务中的所有命令都不会执行。同理,如果客户端在使用MULTI命令开启事务后执行EXEC命令,则事务中的所有命令都会执行。
- Redis中的事务可以使用DISCARD命令来清空一个命令队列,并放弃对事务的执行。如果命令在入队时发生错误,Redis将在客户端调用EXEC命令时拒绝执行并取消事务,但是在EXEC命令执行后发生的错误,Redis将选择自动忽略。
相关指令
multi
标记一个事务块的开始。
exec
执行所有事务块的命令
discard
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a1 name
QUEUED
127.0.0.1:6379> set a2 test
QUEUED
127.0.0.1:6379> get a2
QUEUED
# 清除队列命令
127.0.0.1:6379> discard
OK
# 之后获取就获取不到queue队列了
127.0.0.1:6379> get a2
(nil)
127.0.0.1:6379> get a1
(nil)
watch
Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
WATCH key [key ...]
springboot事务使用
开启事务
方式一
@Autowired
private RedisTemplate redisTemplate;
@Test
void testTransaction(){
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.multi();
ValueOperations<String, String> stringops = redisTemplate.opsForValue();
String key="test:transaction";
stringops.set(key,"1");
ListOperations<String, String> listOps = redisTemplate.opsForList();
String key1="test:transaction2";
listOps.leftPush(key1,"1111");
System.out.println(stringops.get(key));
System.out.println(listOps.range(key1, 0, 10));
redisTemplate.exec();
System.out.println(stringops.get(key));
System.out.println(listOps.range(key1, 0, 10));
}
方式二:使用SessionCallback
@Test
public void testTransaction2(){
redisTemplate.execute(new SessionCallback<List<Object>>(){
@Override
public List<Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi();
operations.opsForValue().set("name:1","walker11");
operations.opsForValue().set("name:2","walker22");
operations.opsForValue().set("name:3","walker33");
return redisTemplate.exec();
}
});
}
使用discard取消事务
@Test
public void testDiscard(){
Integer flag=1;
redisTemplate.execute(new SessionCallback<List<Object>>(){
@Override
public List<Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi();
operations.opsForValue().set("name:1","walker11");
operations.opsForValue().set("name:2","walker22");
operations.opsForValue().set("name:3","walker33");
if(flag.equals(1)){
redisTemplate.discard();
return null;
}
return redisTemplate.exec();
}
});
}
参考文章:https://zhuanlan.zhihu.com/p/146865185
|