赞
踩
redis是支持一定事务能力的NoSQL,在redis中使用事务,通常的命令组合是watch…multi…exe,也就是要在一个redis连接中执行多个命令,这是我们可以考虑使用SessionCallback接口来达到这个目的。
如上redis事务执行流程,首先watch监控redis的一些键;multi命令开启事务,开启事务后,接下来redis命令不会马上被执行,而是存放在一个队列里,这点是需要注意的地方,也就是在这是我们执行一些返回数据的命令,redis也不会马上执行,所以此时调用redis命令,返回的结果都是null;exec命令意义在于执行事务,只是它在队列命令执行前会判断watch监控的redis的键的数据是否发生过变化(即使赋予与之前相同的值也会被认为是变化过),如果发生变化,则redis取消事务,队列中命令全部不执行,否则执行事务,队列中命令全部执行,这里注意如果执行队列中的某一个命令错误,而错误后面的命令依旧被执行,这就是redis事务和数据库事务的不一样,redis事务是先让命令进入队列,一开始并没有检测这个命令是否能成狗,只有在exec命令执行时才发现错误。为了克服这个问题,一般在执行redis事务前,严格的检查数据,避免这样的情况发生。
public Object multi(){ redisTemplate.opsForValue().set("key1","value1"); //SessionCallback实现在同一连接下执行多个redis命令 redisTemplate.execute(new SessionCallback() { @Nullable @Override public Object execute(RedisOperations operations) throws DataAccessException { //设置要监控的key operations.watch("key1"); //开启事务,在exec命令执行前,全部都只是进入队列 operations.multi(); operations.opsForValue().set("key2","value2"); //operations.opsForValue () .increment ("key1", 1); //--1-- //取值将为null,因为redis只是把命令放入队列,并没执行 Object value2=operations.opsForValue().get("key2"); System.out.println("命令在队列,所以value为null【"+value2+"】"); operations.opsForValue().set("key3","value3"); //取值将为null,因为redis只是把命令放入队列,并没执行 Object value3=operations.opsForValue().get("key3"); System.out.println("命令在队列,所以value为null【"+value3+"】"); //执行exec命令,将先判断key是否在监控后被修改过,如果是则不执行事务,否则就执行事务 return operations.exec(); //--2-- } }); return "ok";
为了揭示 Redis 事务的特性,我们对这段代码做以下两种测试。
redis在2.6版本后提供了Lua脚本的支持,而且在执行Lua脚本在redis中还具备原子性,所以在需要保证数据一致性的高并发环境中,我们也可以使用redis的Lua语言来保证数据的一致性,而且Lua脚本具备更加强大的运算功能,在高并发需要保证数据一致性时,Lua脚本方案比使用redis自身提供的事务要更好一些。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。