您的位置:首页 > 数据库 > Redis

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命令结束
例如
> 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之前的命令。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: