Redis(五)-特性-事务
概述
Redis作为数据库使用时自然会想到它对原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)即ACID的支持,本节就来学习下Redis事务
1. 实现
首先,这些命令虽然被客户端发送到了服务器端,但Redis实例只是把这些命令暂存到一个命令队列中,并不会立即执行,当客户端向服务器端发送提交事务的命令,让数据库实际执行第二步中发送的具体操作
-
MULTI
: 开启事务 -
EXEC
: 执行事务 -
DISCARD
: 取消事务 -
WATCH
: 监控key,key的值在事务执行前被修改,则事务执行失败 -
UNWATCH
: 放弃监控
1.
客户端使用命令MULTI
开启事务;
2.
客户端发送操作命令,这些命令被发送到了服务器端,但Redis只是做命令正确性校验,然后把这些命令暂存到一个命令队列中,并不会立即执行;
3.
当客户端端发送提交事务的命令EXEC
,开始实际执行第二步中发送的具体操作
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key1 888
QUEUED
127.0.0.1:6379> set key2 999
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
2. 原子性
原子性即一个事务中多个操作同时完成或同时失败;
redis中不同情况下:
- 命令入队时就报错,会放弃事务,保证原子性
- 命令入队时没报错,实际执行时报错,不保证原子性
- EXEC时实例故障,如果开启了AOF日志(使用redis-check-aof工具),可以保证原子性
总结一下就是Redis对原子性的保证是:要么都运行,要么都不运行
, 而不是:要么都正确运行,要么都不运行
3. 一致性
一致性即数据库中数据整体上在执行前后是一致的
redis本身是非关系型数据库,数据库本身对数据没有约束,不存在一致性的概念
4. 隔离性
隔离性即事务执行过程中,事务访问的数据不被其他操作干扰;
redis实现隔离性有两种方式:
1.
使用WATCH来保证,在开启事务之后执行事务之前,监控数据被修改后事务执行失败

-
客户端使用Pipeline API把命令一次性打包发送到服务端,再加上redis本身单线程,因此也可以保证隔离性
事务-隔离性-pipeline.png
Pipeline p1 = jedis.pipelined();
//开启事务
p1.multi();
p1.incr(key1);
p1.incr(key1);
//提交事务
Response txresult= p1.exec();
//关闭pipeline
p1.sync();
List responses = txresult.get();
5. 持久性
持久性即事务完成后数据被持久化的保存下来不会丢失;
Redis持久性取决于RDB/AOF持久化的配置;但是不管Redis采用什么持久化模式,事务的持久性属性是得不到绝对保证的。
6. 使用建议
1.
在使用事务时,建议配合Pipeline使用
- 如果不使用 Pipeline,客户端一个一个发送命令到服务端,这样消息每次都是一来一回,效率比较低,而且在这多次操作之间,别的客户端可能就把原本准备修改的值给修改了,所以无法保证隔离性。
- 而使用 Pipeline 是一次性把所有命令打包好全部发送到服务端,服务端全部处理完成后返回。这么做好的好处,一是减少了来回网络 IO 次数,提高操作性能。二是一次性发送所有命令到服务端,服务端在处理过程中,是不会被别的请求打断的(Redis单线程特性,此时别的请求进不来),这本身就保证了隔离性。我们平时使用的 Redis SDK 在使用开启事务时,一般都会默认开启 Pipeline 的;
2.
关于 WATCH 命令的使用场景
- 使用了 Pipeline 一次发送所有命令到服务端,那么就不需要使用 WATCH 了,因为服务端本身就保证了隔离性。
- 如果事务 + Pipeline 就可以保证隔离性,那 WATCH 还有没有使用的必要?
答案是有的。对于一个资源操作为读取、修改、写回这种场景,如果需要保证事物的原子性,pipeline就无法实现了,此时就需要用到 WATCH 了。
-------over-------