设为首页 收藏本站
查看: 862|回复: 0

[经验分享] 【Redis】5、Redis事务处理

[复制链接]

尚未签到

发表于 2017-12-20 22:36:50 | 显示全部楼层 |阅读模式
  MULTI 、EXEC 、DISCARD 和WATCH 是 Redis 事务的基础
  1.MULTI 命令用于开启一个事务,它总是返回 OK 。
  MULTI 执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中
  2.EXEC 命令被调用时,所有队列中的命令才会被执行。
  +++++++++++命令 +++++++++++
  

redis 192.168.1.53:6379> multi  
OK
  
redis 192.168.1.53:6379> incr foo
  
QUEUED
  
redis 192.168.1.53:6379> set t1 1
  
QUEUED
  
redis 192.168.1.53:6379> exec
  
1) (integer) 2
  
2) OK
  

  +++++++++++对应的java代码 +++++++++++
  

Jedis jedis = new Jedis("192.168.1.53", 6379);  
Transaction tx = jedis.multi();
  
tx.incr( "foo");
  
tx.set( "t1", "2");
  
List<Object> result = tx.exec();
  

  
if (result == null || result.isEmpty()) {
  System. err.println( "Transaction error...");
  return ;
  
}
  

  
for (Object rt : result) {
  System. out.println(rt.toString());
  
}
  

  使用事务时可能会遇上以下两种错误:
  1.事务在执行EXEC 之前,入队的命令可能会出错。比如说,命令可能会产生语法错误(参数数量错误,参数名错误,等等),或者其他更严重的错误,比如内存不足
  (如果服务器使用 maxmemory 设置了最大内存限制的话)。
  2.命令可能在EXEC 调用之后失败。举个例子,事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面,诸如此类。
  第一种错误的情况:
  服务器端:
  在 Redis 2.6.5 以前,Redis 只执行事务中那些入队成功的命令,而忽略那些入队失败的命令
  不过,从 Redis 2.6.5 开始,服务器会对命令入队失败的情况进行记录,并在客户端调用EXEC 命令时,拒绝执行并自动放弃这个事务。
  +++++++++++命令 +++++++++++
  

redis 192.168.1.53:6379> multi  
OK
  
redis 192.168.1.53:6379> incr foo
  
QUEUED
  
redis 192.168.1.53:6379> set ff 11 22
  
(error) ERR wrong number of arguments for 'set' command
  
redis 192.168.1.53:6379> exec
  
1) (integer) 4
  

  因为我的版本是:2.6.4,所以Redis 只执行事务中那些入队成功的命令,而忽略那些入队失败的命令
  客户端(jredis):
  客户端以前的做法是检查命令入队所得的返回值:如果命令入队时返回 QUEUED ,那么入队成功;否则,就是入队失败。如果有命令在入队时失败,
  那么大部分客户端都会停止并取消这个事务。
  第二种错误的情况:
  至于那些在EXEC 命令执行之后所产生的错误,并没有对它们进行特别处理:即使事务中有某个/某些命令在执行时产生了错误,事务中的其他命令仍然会继续执行。
  +++++++++++命令+++++++++++
  

redis 192.168.1.53:6379> multi  
OK
  
redis 192.168.1.53:6379> set a 11
  
QUEUED
  
redis 192.168.1.53:6379> lpop a
  
QUEUED
  
redis 192.168.1.53:6379> exec
  
1) OK
  
2) (error) ERR Operation against a key holding the wrong kind of value
  

  +++++++++++对应的java代码 +++++++++++
  

Jedis jedis = new Jedis("192.168.1.53", 6379);  
Transaction tx = jedis.multi();
  
tx.set( "t1", "2");
  
tx.lpop( "t1");
  
List<Object> result = tx.exec();
  

  
if (result == null || result.isEmpty()) {
  System. err.println( "Transaction error...");
  return ;
  
}
  

  
for (Object rt : result) {
  System. out.println(rt.toString());
  
}
  

  Redis 在事务失败时不进行回滚,而是继续执行余下的命令
  这种做法可能会让你觉得有点奇怪,以下是这种做法的优点:
  1.Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,
  失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  2.因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
  鉴于没有任何机制能避免程序员自己造成的错误,并且这类错误通常不会在生产环境中出现,所以 Redis 选择了更简单、更快速的无回滚方式来处理事务。
  3.DISCARD  命令时,事务会被放弃,事务队列会被清空,并且客户端会从事务状态中退出
  +++++++++++命令 +++++++++++
  

redis 192.168.1.53:6379> set foo 1  
OK
  
redis 192.168.1.53:6379> multi
  
OK
  
redis 192.168.1.53:6379> incr foo
  
QUEUED
  
redis 192.168.1.53:6379> discard
  
OK
  
redis 192.168.1.53:6379> get foo
  
"1"
  

  4.WATCH  命令可以为 Redis 事务提供 check-and-set (CAS)行为
  被WATCH 的键会被监视,并会发觉这些键是否被改动过了。如果有至少一个被监视的键在EXEC 执行之前被修改了,那么整个事务都会被取消
  +++++++++++第一条命令 +++++++++++
  

redis 192.168.1.53:6379> watch foo  
OK
  
redis 192.168.1.53:6379> set foo 5
  
OK
  
redis 192.168.1.53:6379> multi
  
OK
  
redis 192.168.1.53:6379> set foo 9
  
QUEUED
  

  +++++++++++暂停(执行完第二条命令才执行下面的)+++++++++++
  

redis 192.168.1.53:6379> exec  
(nil)
  
redis 192.168.1.53:6379> get foo
  
"8"
  

  +++++++++++第二条命令+++++++++++
  

redis 192.168.1.53:6379> set foo 8  
OK
  

  +++++++++++对应的java代码 +++++++++++
  

Jedis jedis = new Jedis("192.168.1.53", 6379);  
jedis.watch( "foo");
  
Transaction tx = jedis.multi();
  
tx.incr( "foo");
  

  
List<Object> result = tx.exec();          //运行时在这边打断点,然后通过命令行改变foo的值
  
if (result == null || result.isEmpty()) {
  System. err.println( "Transaction error...");
  return;
  
}
  
for (Object rt : result) {
  System. out.println(rt.toString());
  
}
  

  如果在WATCH 执行之后,EXEC 执行之前,有其他客户端修改了 mykey 的值,那么当前客户端的事务就会失败。程序需要做的,就是不断重试这个操作,直到没有发生碰撞为止。
  这种形式的锁被称作乐观锁,它是一种非常强大的锁机制。并且因为大多数情况下,不同的客户端会访问不同的键,碰撞的情况一般都很少,所以通常并不需要进行重试。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-426252-1-1.html 上篇帖子: window下使用Redis Cluster部署Redis集群 下篇帖子: 就publish/subscribe功能看redis集群模式下的队列技术(一)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表