Redis 事务的特别之处
Oracle/MySQL 等关系型数据库事务的作用之一是保证并发访问下数据的一致性,Redis 事务的意义则有些不同。
Redis server 是单线程处理来自 client 的指令,所以,所有命令的执行都是原子操作。举一个简单的例子,单 Redis server 的情况下,多个 client 并发地执行 INCR(自增)命令,是不会返回相同结果的。
Redis 事务的特点我总结如下:
- Redis 没有线程安全的问题,事务的意义也不在于保证数据的一致性,而是 保证命令的批量顺序执行,且事务执行期间,Redis 不会执行来自 client 的其他请求
- 事务执行过程中,如果有命令执行失败,事务不会终止,而是会继续执行剩下的命令,Redis 没有异常回滚
对「Redis 事务命令要么全部执行,要么全部不执行」这句事实的理解:
- 事务一旦开始执行,就无法中止,也无法回滚
- 事务中某条语句的执行结果是错误时,redis 继续执行剩下的指令
- 事务命令全部不执行的几种情况
- 没有执行 EXEC 命令(事务实际上没有开始)
- WATCH 的 key 发生改变
- DISCARD 命令放弃事务
本质上,开启事务后,所有输入的命令都被缓存在一个队列中,一旦调用 EXEC 命令,队列里的指令被一条一条的执行。
Redis 事务的关键 API
- MULTI: 开启事务
- EXEC: 执行任务队列里所有命令,并结束事务
- DISCARD: 放弃事务,清空任务队列,全部不执行,并 UNWATCH
- WATCH key [key1]: MULTI 执行之前,指定监控某 key,如果 key 发生修改,放弃整个事务执行
- UNWATCH: 手动取消监控
使用 Spring Data Redis 操作事务
这几天在做项目的时候,用到了 spring-data-redis 提供的 RedisTemplate 来操作 Redis。关于事务操作的时候会有问题,我是这样写的:
|
|
代码执行后报错:“No ongoing transaction. Did you forget to call multi? ”,查了一下,RedisTemplate 操作事务不能理所当然地像原生 API 那么写,其实使用 RedisTemplate 操作事务需要自己实现 SessionCallBack 的 execute 方法来实现事务:
|
|