discard:取消事务,放弃执行事务块内的所有命令。如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH
watch:监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断,watch不会开启事务。
unwatch:取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。因为 EXEC 命令会执行事务,因此 WATCH 命令的效果已经产生了;而 DISCARD 命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 UNWATCH 了。
[plain] view plain copy PRint?二、代码实例
[java] view%20plain copy print?1.当事务执行t.exec()的时候,事务内的命令才会连续执行,并且中间不会插入其它client的命令。2.一个Redis的jedis 只能开启一个事务,开启多个会抛异常。3.watch操作并不一定非要在事务内操作,也可以在事物外进行watch。redis只能保证事务的每个命令连续执行,但是如果事务中的一个命令失败了,并不回滚其他命令,比如使用的命令类型不匹配。当事务的执行过程中,如果redis意外的挂了。很遗憾只有部分命令执行了,后面的也就被丢弃了。当然如果我们使用的append-only file方式持久化,redis会用单个write操作写入整个事务内容。即是是这种方式还是有可能只部分写入了事务到磁盘。发生部分写入事务的情况下,redis重启时会检测到这种情况,然后失败退出。可以使用redis-check-aof工具进行修复,修复会删除部分写入的事务内容。修复完后就能够重新启动了。参考:http://blog.csdn.net/freebird_lb/article/details/7734008
三、总结
1.redis事物实现,multi开始,所有指令会被放入到队列中。当调用exec后,队列中所有指令会依次被执行。2.multi-exec中指令执行时,所有指令只要语法合理都会被写入队列中。队列执行时,指令有可能会执行失败,但不影响其它指令执行。3.redis事物提供了乐观锁,通过watch指令可以实现CAS操作。watch–multi–exec操作在给key加上乐观锁后,当在执行exec指令前,有其它client修改此key,此事物将执行失败。从而保证原子操作。说明:对于redis事物的应用其实需要灵活使用,上面介绍的例子是从官网翻译而来。其实在实际中可以通过watch一些标记位来保证多线程下缓存与数据库数据库的一致性。(我们的系统是分布式缓存与数据库的结合使用,缓存需要跟据数据库的一致性很重要,下面举例我们应用中的一个场景:)如一个service方法,serviceA,执行DAO方法(1),然后更新缓存(2),两个并发线程,线程一执行了方法1,此刻他需要把DAO相关的数据更新到缓存2中,多线程情况下,线程二在线程一执行1后,也同样执行1,2相关的操作,并且比线程一优先完成,这样将导致线程一在执行2时,将出现缓存数据与数据库不一致的现象。(以上是针对单帐号的多并发操作,发生的概率还是存在),对于以上问题我们的解决方案是:1. 帐号为acc,为每个acc在缓存中增加一个tag标识.2. 当线程一执行方法1前,设置标记位tag.3. 当执行方法2时,将会watch tag,并且比较tag是否发生了修改,如果一旦发生修改,则此次缓存操作不将更新,并清空此acc缓存。4. 如果tag值达到预期,则提交缓存更新,在提交缓存这段时间,如果tag发生变换,则redisexec提交时,会返回null ,这样,虽然缓存内容更新成功,但跟据返回结果,可以即时清除此acc的缓存,从而清空了缓存的脏数据。5. 通过以上事物保证了缓存数据与数据库数据不一致性的时间很短,甚至可以忽略,因为基本上在MS级别上。6. 我们的应用在缓存数据不存在acc的情况下,会尝试从数据库读取,而缓存的作用只是缓解我们系统数据库的压力,这样实现,很好的达到了我们的预期效果.
参考:
1.redis事务介绍与应用
新闻热点
疑难解答