0%

redis事务

redis事务

注意:我使用的版本是6.0.10,不同版本可能略有差别

redis事务就是一组命令的集合,一个事务中所有命令都会序列化,按顺序的串行化执行而不会被其他命令插入

  • Redis的事务仅仅是保证事务里的操作会被连续独占的执行,因为是单线程架构,在执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的

  • Redis的事务没有隔离级别的概念,因为事务提交前任何指令都不会被实际执行,也就不存在事务内的查询要看到事务里的更新,在事务外查询不能看到这种问题了

  • Redis的事务不保证原子性,也就是不保证所有指令同时成功或同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力

事务的常用命令

  • multi 标记一个事务块的开始,后续命令逐个放入队列中
  • exec 执行事务块的命令
  • discard 取消事务,丢弃事务块的命令,需要在exec之前
  • watch key [key …] 监视key,如果在事务执行之前,这个key被其他命令所改动,则事务中断。watch要在multi之前进行执行
  • unwatch 取消监视所有key

事务的执行

1
2
3
4
5
6
7
8
9
10
11
12
13
#标注事务的开始
MULTI
OK
#在事务内部的操作全是入队,不会真正执行
set tran1 v1
QUEUED
set tran2 v2
QUEUED
#执行,由于redis单线程的特性,在执行一个事务的执行队列时,中间不会有其他指令打搅。只能说事务是隔离的
exec
1) OK
2) OK

redis的事务没有隔离级别的概念,并且不会保证原子性

  • 如果任何一个命令语法有错,Redis会直接返回错误,所有的命令都不会执行
  • 如果某个命令执行错误,那么其它的命令仍然会正常执行,然后在执行后返回错误信息
  • Redis不提供事务回滚的功能,开发者必须在事务执行出错后,自行恢复数据库状态

watch监视

watch指令类似于乐观锁,在事务开始之前使用,如果在watch之后有任何所监视的key发生变化,exec指令所执行的事务将会被放弃,当 EXEC 被调用后,所有的之前被监视的键值会被取消监视,不管事务是否被取消或者执行。并且当客户端连接丢失的时候,所有东西都会被取消监视

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#设值
set balance 100
OK
#监视
watch balance
OK
#修改
set balance 200
OK
get balance
"200"
#开启事务
MULTI
OK
#修改入队
DECRBY balance 10
QUEUED
#执行失败
exec
(nil)
get balance
"200"

redis只能保证事务中的操作顺序执行,但是如果事务中有一条命令失败了,并不会回滚其他命令

事务可以搭配管道一起使用,来减少网络读写次数

1
2
3
4
5
6
7
8
9
10
11
12
13
List<Object> pipelined = stringRedisTemplate.executePipelined(
new SessionCallback<Object>() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
operations.multi();
operations.opsForValue().increment("k1");
operations.opsForValue().increment("k2");
operations.exec();
return null;
}
}
);
System.out.println(pipelined.get(0));

欢迎关注我的其它发布渠道