Redis研究(十)―Redis事务和生存时间

2024-04-26

Redis研究(十)―Redis事务和生存时间(通用4篇)

篇1:Redis研究(十)―Redis事务和生存时间

一、事务概述

Redis事务是一组命令的集合,事务同命令一样是Redis的最小执行单位,要么执行,要么不执行。

事务的原理是先将属于一个事务的命令发送给Redis,然后在让Redis依次执行这些命令。

Redis在事务中没有立即执行sadd操作,而是返回QUEUED表示这两条命令已经进入等待执行的事务队列中了。vcD4KPHA+yrnTw0VYRUPD/MHuuObL31JlZGlzvau1yLT91rTQ0LXEysLO8bbTwdDW0LXEy/nT0MP8we6wtNXVt6LLzcuz0PLSwLTO1rTQ0KGjPC9wPgo8cD5FWEVDt7W72CYjMjA1NDA7vs3Kx9Xi0KnD/MHutcS3tbvYJiMyMDU0MDvX6bPJtcTB0LHto6y3tbvYJiMyMDU0MDvLs9Dyus3D/MHutcTLs9Dyz+DNrKGjPC9wPgoKPHA+UmVkaXOxo9ak0ru49srCzvHW0LXEy/nT0MP8we7SqsO0trzWtNDQo6zSqsO0tryyu9a00NCho8jnufvU2reiy81FWEVDw/zB7sewv827p7bLts/P38HLo6zU8lJlZGlzu+HH5b/VysLO8bbTwdCjrMrCzvHW0LXEy/nT0MP8we62vLK7u+HWtNDQoaO2+NK7tam/zbuntsu3osvNwctFWEVDw/zB7qOsy/nT0LXEw/zB7r7Ntry74da00NCjrLy0yrm0y7rzv827p7bLts/P39Kyw7vT0LnYz7WjrNLyzqpSZWRpc9bQ0tG+rbzHwrzBy8v509DSqta00NC1xMP8we6hozwvcD4KCjxwPlJlZGlztcTKws7xu7nE3LGj1qTSu7j2ysLO8cTatcTD/MHu0sC0zta00NC2+LK7sbvG5Mv7w/zB7rLlyOuhozwvcD4KPHA+PHN0cm9uZz48YnI+Cjwvc3Ryb25nPjwvcD4KPHA+PHN0cm9uZz62/qGitO3O87SmwO08L3N0cm9uZz48L3A+CjxwPsrCzvHW0LXExLO49sP8we7WtNDQs/a07aOs1PXDtLDso788L3A+CjxwPqOoMaOp0++3qLTtzvOjrNa4w/zB7rK7tObU2rvy1d/D/MHuss7K/bXEuPbK/bK7ttShozwvcD4KPHA+PGltZyBzcmM9”www.2cto.com/uploadfile/Collfiles/0119/2015011909522880.png“ alt=”“>

3个命令,一个正确,两个错误,而只要有一个命令有语法错误,执行EXEC命令后Redis就会直接返回错误,连语法正确的命令也不会执行。

(2)运行错误,指命令执行时出现的错误,比如使用散列类型的命令操作集合类型的键。在执行以前Redis无法发现,所以在事务中这样的命令会被接受并执行,

一条命令出现了运行错误,事务里其他的命令依然会继续执行。

虽然sadd key 2出现了错误,但是set key 3依然执行了,

Redis事务没有回滚功能。

Redis不支持回滚功能,也使得Redis在事务上可以保持简洁和快速。两种错误,语法错误和运行错误完全可以在开发时找出并解决。

三、watch命令

事务中每个命令的执行结果都是最后一期返回的,无法将前一条命令的结果作为下一条命令的参数。

比如说get值,+1,再set

为了解决这个问题,在get获得键值后保证该键值不被其他客户端修改,直到函数执行完成后才允许其他客户端修改该键值。可以防止竞态条件。

执行watch命令后,事务执行前修改了key的值,set key 2,所以最后事务中的命令set key 3没有执行,EXEC命令返回空结果。

由于watch命令的作用只是当被监控的键值被修改后阻止之后一个事务的执行,而不能保证其他客户端不修改这一键值,所以我们需要在EXEC执行失败后重新执行整个函数。

执行EXEC后会取消所有键的监控,也可以用unwatch命令来取消监控。

四、生存时间

使用expire命令设置一个键的生存时间,到时候后redis会自动删除它。

如果想让session:29e3d键在15分钟后被删除

返回1表示成功,0表示键不存在或者设置失败。

一个键还有多久时间被删除,可以用ttl命令,返回值是键的剩余时间(单位s)

当键不存在时ttl返回-1.同样会返回-1是没有为键设置生存时间(永久存在)。

想取消生存时间设置,即恢复永久,用persist命令。成功1,失败0

除次之外,还可以set或getset命令为键赋值也会同时清除键的生存时间。

使用expire会重新设置键的生存时间。

其他只对键值进行操作的命令(incr、lpush、hset、zrem)都不会影响键的生存时间。

expire命令时间参数必须是整数,s。更精确,使用pexpire,单位是毫秒。对应可以用pttl返回剩余时间。

如果watch命令监测了一个拥有生存时间的键,该键时间到期后自动删除并不会被watch命令认为该键被改变。

另外两个命令

expireat和pexpireat,与前面差别使用unix时间作为时间参数。expireat单位是秒,pexpireat单位是毫秒。

篇2:Redis研究(十)―Redis事务和生存时间

#在Shell命令行下执行Redis的客户端工具。 />redis-cli #在当前连接上启动一个新的事务。 redis 127.0.0.1:6379>multi OK #执行事务中的第一条命令,从该命令的返回结果可以看出,该命令并没有立即执行,而是存于事务的命令队列。 redis 127.0.0.1:6379>incr t1 QUEUED #又执行一个新的命令,从结果可以看出,该命令也被存于事务的命令队列。 redis 127.0.0.1:6379>incr t2 QUEUED #执行事务命令队列中的所有命令,从结果可以看出,队列中命令的结果得到返回。 redis 127.0.0.1:6379>exec 1) (integer) 1 2) (integer) 1

篇3:Redis学习手册(事务)

#在Shell命令行下执行Redis的客户端工具。 />redis-cli #在当前连接上启动一个新的事务。 redis 127.0.0.1:6379>multi OK #执行事务中的第一条命令,从该命令的返回结果可以看出,该命令并没有立即执行,而是存于事务的命令队列。 redis 127.0.0.1:6379>incr t1 QUEUED #又执行一个新的命令,从结果可以看出,该命令也被存于事务的命令队列。 redis 127.0.0.1:6379>incr t2 QUEUED #执行事务命令队列中的所有命令,从结果可以看出,队列中命令的结果得到返回。 redis 127.0.0.1:6379>exec 1) (integer) 1 2) (integer) 1

篇4:Redis教程(八):事务详解

一、概述:

和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制,在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石。相信对有关系型数据库开发经验的开发者而言这一概念并不陌生,即便如此,我们还是会简要的列出Redis中事务的实现特征:

1). 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。

2). 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。

3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为”BEGIN TRANSACTION“语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。

4). 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。

5). 当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。

二、相关命令列表:

命令原型时间复杂度命令描述返回值MULTI用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才会被原子的执行。始终返回OKEXEC执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了WATCH命令,那么只有当WATCH所监控的Keys没有被修改的前提下,EXEC命令才能执行事务队列中的所有命令,否则EXEC将放弃当前事务中的所有命令。原子性的返回事务中各条命令的返回结果。如果在事务中使用了WATCH,一旦事务被放弃,EXEC将返回NULL-multi-bulk回复。DISCARD回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果WATCH命令被使用,该命令将UNWATCH所有的Keys。始终返回OK。WATCHkey [key ...]O(1)在MULTI命令执行之前,可以指定待监控的Keys,然而在执行EXEC之前,如果被监控的Keys发生修改,EXEC将放弃执行该事务队列中的所有命令。始终返回OK。UNWATCHO(1)取消当前事务中指定监控的Keys,如果执行了EXEC或DISCARD命令,则无需再手工执行该命令了,因为在此之后,事务中所有被监控的Keys都将自动取消。始终返回OK。

三、命令示例:

1. 事务被正常执行:

代码如下:

#在Shell命令行下执行Redis的客户端工具。

/> redis-cli

#在当前连接上启动一个新的事务。

redis 127.0.0.1:6379> multi

OK

#执行事务中的第一条命令,从该命令的返回结果可以看出,该命令并没有立即执行,而是存于事务的命令队列。

redis 127.0.0.1:6379> incr t1

QUEUED

#又执行一个新的命令,从结果可以看出,该命令也被存于事务的命令队列。

redis 127.0.0.1:6379> incr t2

QUEUED

#执行事务命令队列中的所有命令,从结果可以看出,队列中命令的结果得到返回。

redis 127.0.0.1:6379> exec

1) (integer) 1

2) (integer) 1

2. 事务中存在失败的命令:

代码如下:

#开启一个新的事务,

redis 127.0.0.1:6379> multi

OK

#设置键a的值为string类型的3。

redis 127.0.0.1:6379> set a 3

QUEUED

#从键a所关联的值的头部弹出元素,由于该值是字符串类型,而lpop命令仅能用于List类型,因此在执行exec命令时,该命令将会失败。

redis 127.0.0.1:6379> lpop a

QUEUED

#再次设置键a的值为字符串4。

redis 127.0.0.1:6379> set a 4

QUEUED

#获取键a的值,以便确认该值是否被事务中的第二个set命令设置成功。

redis 127.0.0.1:6379> get a

QUEUED

#从结果中可以看出,事务中的第二条命令lpop执行失败,而其后的set和get命令均执行成功,这一点是Redis的事务与关系型数据库中的事务之间最为重要的差别。

redis 127.0.0.1:6379> exec

1) OK

2) (error) ERR Operation against a key holding the wrong kind of value

3) OK

4) ”4“

3. 回滚事务:

代码如下:

#为键t2设置一个事务执行前的值。

redis 127.0.0.1:6379> set t2 tt

OK

#开启一个事务。

redis 127.0.0.1:6379> multi

OK

#在事务内为该键设置一个新值。

redis 127.0.0.1:6379> set t2 ttnew

QUEUED

#放弃事务。

redis 127.0.0.1:6379> discard

OK

#查看键t2的值,从结果中可以看出该键的值仍为事务开始之前的值。

redis 127.0.0.1:6379> get t2

”tt“

四、WATCH命令和基于CAS的乐观锁:

在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能。假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Null multi-bulk应答以通知调用者事务执行失败。例如,我们再次假设Redis中并未提供incr命令来完成键值的原子性递增,如果要实现该功能,我们只能自行编写相应的代码。其伪码如下:

代码如下:

val = GET mykey

val = val + 1

SET mykey $val

以上代码只有在单连接的情况下才可以保证执行结果是正确的,因为如果在同一时刻有多个客户端在同时执行该段代码,那么就会出现多线程程序中经常出现的一种错误场景--竞态争用(race condition)。比如,客户端A和B都在同一时刻读取了mykey的原有值,假设该值为10,此后两个客户端又均将该值加一后set回Redis服务器,这样就会导致mykey的结果为11,而不是我们认为的12。为了解决类似的问题,我们需要借助WATCH命令的帮助,见如下代码:

代码如下:

WATCH mykey

val = GET mykey

val = val + 1

MULTI

SET mykey $val

EXEC

上一篇:写妈妈的1000字作文下一篇:华东师大考研真题