Redis学习笔记1 事务
2017-05-21 13:20
330 查看
有关事务的命令
MULTI: 事务开始
EXEC: 事务提交
DISCARD: 事务取消
WATCH:监控某些key。
事务提交时(EXEC), Redis会判断这些被Watched的Key是否被改变。 如果有,则事务失败,不提交;否则事务提交。
注意,如果是和Trasaction同一个Redis client在Transaction中(即在multi/exec之间),改变了被Watched的值,是不会影响事务提交的。这是合理的。
换个角度看,下面的行为会使事务提交失败
其它Redis client改变了watched的keys
本Redis client,但在事务之外(即在watch之后,multi之前)改变了keys
可以使用UNWATCH命令去取消对某些Keys的监控
当exec被执行后,所有keys被UNWATCH.
用法
以MULTI命令开始
以EXEC或DISCARD命令结束
例如
说明
Redis
Transaction保证事务中的命令,要么所有都被执行,或者所有都不被执行。
Transaction中的命令,如果出错,不会rollback之前的命令,即有可能某些命令成功了,有些命令失败了。所以Redis
Transacation只是保证所有命令被执行或取消,并不关心某个命令的运行是否报错
例1 基本事务操作
输出结果
例2 在例1的基础上,模拟value2被更改
因此在test2的事务提交(tx.exec())时,redis发现value2被其它客户端修改了,本事务的所有命令被取消。
本例输出如下
例3. 模拟事务中命令出错
运行结果
value2是字符型的值,做incr操作时会报错。但value1的incr操作依然成功,值被改为了101. 所以redis的事务只是保证事务中命令被全部执行或全部不执行,并不关心每条命令是否出错,出错后不会rollback之前的命令。
MULTI: 事务开始
EXEC: 事务提交
DISCARD: 事务取消
WATCH:监控某些key。
事务提交时(EXEC), Redis会判断这些被Watched的Key是否被改变。 如果有,则事务失败,不提交;否则事务提交。
注意,如果是和Trasaction同一个Redis client在Transaction中(即在multi/exec之间),改变了被Watched的值,是不会影响事务提交的。这是合理的。
换个角度看,下面的行为会使事务提交失败
其它Redis client改变了watched的keys
本Redis client,但在事务之外(即在watch之后,multi之前)改变了keys
可以使用UNWATCH命令去取消对某些Keys的监控
当exec被执行后,所有keys被UNWATCH.
用法
以MULTI命令开始
以EXEC或DISCARD命令结束
例如
> MULTI OK > INCR foo QUEUED > INCR bar QUEUED > EXEC 1) (integer) 1 2) (integer) 1
说明
Redis
Transaction保证事务中的命令,要么所有都被执行,或者所有都不被执行。
Transaction中的命令,如果出错,不会rollback之前的命令,即有可能某些命令成功了,有些命令失败了。所以Redis
Transacation只是保证所有命令被执行或取消,并不关心某个命令的运行是否报错
例1 基本事务操作
private static XStream xs = new XStream(); @Test public void test1() { Jedis jedis = MyJedisPool.getJedis(); jedis.set("value1", "100"); jedis.set("value2", "200"); jedis.watch("value1", "value2"); Transaction tx = jedis.multi(); tx.incr("value1"); tx.incr("value2"); List<Object> result = tx.exec(); System.out.println(xs.toXML(result)); String value1 = jedis.get("value1"); String value2 = jedis.get("value2"); System.out.println("value1=" + value1); System.out.println("value2=" + value2); MyJedisPool.recycleJedisOjbect(jedis); }
输出结果
<list> <long>101</long> <long>201</long> </list> value1=101 value2=201事务中两条命令都成功了,value1和value2被加1
例2 在例1的基础上,模拟value2被更改
private void changeValue2() { Jedis jedis = MyJedisPool.getJedis(); // get a new client connection jedis.incr("value2"); MyJedisPool.recycleJedisOjbect(jedis); } @Test public void test2() { Jedis jedis = MyJedisPool.getJedis(); jedis.set("value1", "100"); jedis.set("value2", "200"); jedis.watch("value1", "value2"); Transaction tx = jedis.multi(); tx.incr("value1"); tx.incr("value2"); changeValue2(); List<Object> result = tx.exec(); System.out.println(xs.toXML(result)); String value1 = jedis.get("value1"); String value2 = jedis.get("value2"); System.out.println("value1=" + value1); System.out.println("value2=" + value2); MyJedisPool.recycleJedisOjbect(jedis); }和例1相比,在test2方法中,增加了调用了一个方法"changeValue2()", 这个方法会获取一个新的redis client connection, 修改value2.
因此在test2的事务提交(tx.exec())时,redis发现value2被其它客户端修改了,本事务的所有命令被取消。
本例输出如下
<empty-list/> value1=100 value2=201
例3. 模拟事务中命令出错
@Test public void test3() { Jedis jedis = MyJedisPool.getJedis(); jedis.set("value1", "100"); jedis.set("value2", "hello"); Transaction tx = jedis.multi(); tx.incr("value1"); tx.incr("value2"); List<Object> result = tx.exec(); System.out.println(xs.toXML(result)); String value1 = jedis.get("value1"); String value2 = jedis.get("value2"); System.out.println("value1=" + value1); System.out.println("value2=" + value2); MyJedisPool.recycleJedisOjbect(jedis); }
运行结果
<list> <long>101</long> <redis.clients.jedis.exceptions.JedisDataException> <detailMessage>ERR value is not an integer or out of range</detailMessage> <stackTrace> <trace>redis.clients.jedis.Protocol.processError(Protocol.java:127)</trace> <trace>redis.clients.jedis.Protocol.process(Protocol.java:161)</trace> <trace>redis.clients.jedis.Protocol.processMultiBulkReply(Protocol.java:206)</trace> <trace>redis.clients.jedis.Protocol.process(Protocol.java:157)</trace> <trace>redis.clients.jedis.Protocol.read(Protocol.java:215)</trace> <trace>redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)</trace> <trace>redis.clients.jedis.Connection.getRawObjectMultiBulkReply(Connection.java:285)</trace> <trace>redis.clients.jedis.Connection.getObjectMultiBulkReply(Connection.java:291)</trace> <trace>redis.clients.jedis.Transaction.exec(Transaction.java:47)</trace> <trace>com.cloudboy.redis.TransactionTest.test3(TransactionTest.java:73)</trace> <trace>sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)</trace> <trace>sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)</trace> <trace>sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)</trace> <trace>java.lang.reflect.Method.invoke(Unknown Source)</trace> <trace>org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)</trace> <trace>org.junit.internal.runners.mo 4000 del.ReflectiveCallable.run(ReflectiveCallable.java:12)</trace> <trace>org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)</trace> <trace>org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)</trace> <trace>org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)</trace> <trace>org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)</trace> <trace>org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)</trace> <trace>org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)</trace> <trace>org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)</trace> <trace>org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)</trace> <trace>org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)</trace> <trace>org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)</trace> <trace>org.junit.runners.ParentRunner.run(ParentRunner.java:363)</trace> <trace>org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)</trace> <trace>org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)</trace> <trace>org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)</trace> <trace>org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)</trace> <trace>org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)</trace> <trace>org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)</trace> </stackTrace> <suppressedExceptions class="java.util.Collections$UnmodifiableRandomAccessList" resolves-to="java.util.Collections$UnmodifiableList"> <c class="list"/> <list reference="../c"/> </suppressedExceptions> </redis.clients.jedis.exceptions.JedisDataException> </list> value1=101 value2=hello
value2是字符型的值,做incr操作时会报错。但value1的incr操作依然成功,值被改为了101. 所以redis的事务只是保证事务中命令被全部执行或全部不执行,并不关心每条命令是否出错,出错后不会rollback之前的命令。
相关文章推荐
- 【学习笔记】Redis(4)-事务
- 四 redis学习笔记之事务
- redis 学习笔记——数据同步、事务
- Redis学习笔记6--Redis事务
- Redis系列学习笔记12 事务
- Redis学习笔记:事务
- Redis学习笔记(九)——事务进阶
- Redis 学习笔记(一):安装配置、发布订阅与事务
- 「Redis学习笔记」事务和错误处理
- Redis学习笔记八、事务
- redis学习笔记 - Pipeline与事务
- 四 redis学习笔记之事务
- 【Redis学习笔记(七)】 Redis中的事务
- [Redis学习笔记]-Redis 事务
- Redis 事务学习笔记
- 四 redis学习笔记之事务
- redis学习笔记---redis特性(expire、事务、数据排序、config命令)
- Redis学习笔记(八)事务 和 连接相关命令
- 四 redis学习笔记之事务
- 七 redis学习笔记之持久化