Redis中的事务(transaction)是一组命令的集合。事务同命令同样都是Redis的最小执行单位,一个事务中的命令要么都执行,要么都不执行。redis
事务的原理是先将属于一个事务的命令发送给Redis,而后再让Redis依次执行这些命令。算法
> MULTI OK > SADD key1 1 QUEUED > SADD key2 2 QUEUED > EXEC 1) (integer) 1 2) (integer) 1
首先用MULTI开启事务,redis会返回"OK"。
接下来输入的命令都会被加入到等待执行的事务队列中,而不是像一般同样当即执行,redis会返回"QUEUED"表示成功加入到队列中了。数据库
最终须要执行时,使用EXEC命令告诉Redis将等待执行的事务队列中的全部命令按照发送的顺序依次执行。EXEC命令的返回值就是这些命令的返回值组成的列表,返回值顺序和命令的顺序相同。缓存
经过这种方式,Redis能够保证一个事务中的全部命令要么都执行,要么都不执行。若是在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的全部命令都不会执行。而一旦客户端发送了EXEC命令,全部的命令就都会被执行,即便此后客户端断线也不要紧,由于Redis中已经记录了全部要执行的命令。服务器
除此以外,Redis的事务还能保证一个事务内的命令依次执行而不被其余命令插入。好比在客户端A执行多条命令的时候,客户端B也刚好发送了一条命令,若是不使用事务,则客户端B的命令可能会插入到客户端A的命令中执行。而使用事务也能够避免这种状况的发生。dom
若是事务中的某个命令执行错误,Redis怎么处理呢?分两种状况:spa
> MULTI OK > SET key value QUEUED > SET key (error)ERR wrong number of arguments for 'set' command > ERRORCOMMAND key (error)ERR unknown command 'ERRORCOMMAND > EXEC (error) EXECABORT Transaction discarded because of previous errors.
这里一共三条命令,第一条被加入到事务队列中,但后面两条都报错,最终事务会被取消执行。unix
> MULTI OK > SET key 1 QUEUED > SADD key 2 QUEUED > SET key 3 QUEUED > EXEC 1)OK 2) (error) ERR Operation against a key holding the wrong kind of value 3)OK > GET key "3"
虽然SADD那一步执行错误,但接下来的SET key 3仍然执行了,key的最终结果为3。
遇到这种状况怎么办呢?可能第一反应是如何回滚,但Redis并无提供事务的回滚功能,一旦出现这类运行错误,须要使用者自行处理,手动将数据库修复为事务执行前的状态。code
但换个角度,正是因为Redis舍弃了事务的回滚功能,使得Redis在的事务简洁、快速。这里的第一种错误能够被Redis识别,第二种错误也是能够提早避免的。队列
在一个事务中只有当全部命令都依次执行完后才能获得每一个结果的返回值,但是有些状况下须要先得到一条命令的返回值,而后再根据这个值执行下一条命令。若是直接获取,可能以后这个值已经被别的客户端更改过了,那么后面都是基于过期的值在作计算了。
为了不这种状况,就可使用WATCH。
WATCH命令能够监控一个或多个键,一旦其中有一个键被修改(或删除),以后的事务就不会执行。监控一直持续到EXEC命令(事务中的命令是在EXEC以后才执行的,因此在MULTI命令后能够修改WATCH监控的键值),如:
> SET key 1 OK > WATCH key OK > SET key 2 OK > MULTI OK > SET key 3 QUEUED > EXEC (nil) > GET key "2"
这个例子中,在执行WATCH命令后、事务执行前修改了key的值(即SET key 2),因此最后事务中的命令SET key 3没有执行,EXEC命令返回空结果。
执行EXEC命令后会取消对全部键的监控,若是不想执行事务中的命令也可使用UNWATCH命令来取消监控。
Redis中能够为键设置生存时间,能够利用这一特性,实现缓存、验证码等功能。
EXPIRE key seconds PEXPIRE key milliseconds
其中seconds/milliseconds参数表示键的生存时间,单位是秒/毫秒。返回1表示设置成功,返回0则表示键不存在或设置失败。
再次执行EXPIRE/PEXPIRE会重置键的生存时间。
还能够经过设置截至时间的方式让键失效:
EXPIREAT key unixtimespan PEXPIREAT key unixtimespan
一样的,PEXPIREAT的单位是毫秒。
若是想取消键的生存时间设置,即将键恢复成永久有效,可使用PERSIST命令:
PERSIST key
若是生存时间被成功清除则返回1,若是键不存在或键原本就是永久的则返回0。
除了这种方法,用SET命令为键复制也会清除键的生存时间。
查看一个键剩余的生存时间:
TTL key PTTL key
TTL和PTTL返回值的单位分别是秒和毫秒。
但若是键不存在,会返回-2。若是键没有设置生存时间,或生存时间设置被清除,会返回-1。
基于生存时间能够将Redis用做缓存。
当服务器内存有限时,若是大量地使用缓存键且生存时间设置得过长就会致使Redis占满内存;另外一方面若是为了防止Redis占用内存过大而将缓存键的生存时间设得过短,就可能致使缓存命中率太低而且大量内存白白地闲置。实际开发中会发现很难为缓存键设置合理的生存时间,为此能够限制Redis可以使用的最大内存,并让Redis按照必定的规则淘汰不须要的缓存键,这种方式在只将Redis用做缓存系统时很是实用。
修改配置文件的maxmemory参数能够限制Redis最大可用内存大小,当超出了这个限制时Redis会依据maxmemory-policy参数指定的策略来删除不须要的键,直到Redis占用的内存小于指定内存。
maxmemory-policy可选的规则以下:
规则 | 说明 |
---|---|
volatile-lru | 使用LRU算法删除一个键(只对设置了生存时间的键) |
allkeys-lru | 使用LRU算法删除一个键 |
volatile-random | 随机删除一个键(只对设置了生存时间的键) |
allkeys-random | 随机删除一个键 |
volatile-ttl | 删除生存时间最近的一个键 |
noeviction | 不删除键,只返回错误 |
LRU(LeastRecently Used)算法即“最近最少使用算法”,认为最近最少使用的键在将来一段时间内也不会被用到,因此当须要空间时这些键会首先被删除。