聊聊redis的事務操作
阿新 • • 發佈:2018-12-10
序
本文主要研究一下redis的事務操作
命令
multi與exec
- 命令列
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr total
QUEUED
127.0.0.1:6379> incr len
QUEUED
127.0.0.1:6379> exec
1) (integer) 2
2) (integer) 2
127.0.0.1:6379> get total
"2"
127.0.0.1:6379> get len
"2"
- lettuce例項
@Test public void testMultiExec(){ RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0"); StatefulRedisConnection<String, String> connection = client.connect(); RedisCommands<String, String> syncCommands = connection.sync(); syncCommands.set("hello","1"); syncCommands.set("world","2"); syncCommands.multi(); syncCommands.incr("hello"); syncCommands.incr("world"); //DefaultTransactionResult[wasRolledBack=false,result=[1, 2, 1, 3, 1]] TransactionResult transactionResult = syncCommands.exec(); System.out.println(transactionResult); System.out.println(syncCommands.get("hello")); System.out.println(syncCommands.get("world")); }
部分執行
- 命令列
127.0.0.1:6379> multi OK 127.0.0.1:6379> set a hello QUEUED 127.0.0.1:6379> set b world QUEUED 127.0.0.1:6379> incr a QUEUED 127.0.0.1:6379> set c part QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) (error) ERR value is not an integer or out of range 4) OK 127.0.0.1:6379> get a "hello" 127.0.0.1:6379> get b "world" 127.0.0.1:6379> get c "part"
- lettuce例項
@Test public void testMultiExecError(){ RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0"); StatefulRedisConnection<String, String> connection = client.connect(); RedisCommands<String, String> syncCommands = connection.sync(); syncCommands.multi(); syncCommands.set("a","hello"); syncCommands.set("b","world"); syncCommands.incr("a"); syncCommands.set("c","part"); //DefaultTransactionResult[wasRolledBack=false,result=[OK, OK, io.lettuce.core.RedisCommandExecutionException: ERR value is not an integer or out of range, OK, 1]] TransactionResult transactionResult = syncCommands.exec(); System.out.println(transactionResult); System.out.println(syncCommands.get("a")); System.out.println(syncCommands.get("b")); System.out.println(syncCommands.get("c")); }
multi與discard
- 命令列
127.0.0.1:6379> set sum 1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr sum
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get sum
"1"
- lettuce例項
@Test
public void testMultiDiscard(){
RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0");
StatefulRedisConnection<String, String> connection = client.connect();
RedisCommands<String, String> syncCommands = connection.sync();
syncCommands.incr("key1");
syncCommands.multi();
syncCommands.incr("key1");
//需要有multi才可以執行discard,成功返回OK
String result = syncCommands.discard();
System.out.println(result);
System.out.println(syncCommands.get("key1"));
}
check and set
@Test
public void testWatch(){
RedisClient client = RedisClient.create("redis://192.168.99.100:6379/0");
StatefulRedisConnection<String, String> connection = client.connect();
RedisCommands<String, String> syncCommands = connection.sync();
String key = "key";
syncCommands.watch(key);
//another connection
StatefulRedisConnection<String, String> conn2 = client.connect();
RedisCommands<String, String> syncCommands2 = conn2.sync();
syncCommands2.set(key, "a");
syncCommands.multi();
syncCommands.append(key, "b");
//DefaultTransactionResult [wasRolledBack=true, responses=0]
TransactionResult transactionResult = syncCommands.exec();
System.out.println(transactionResult);
System.out.println(syncCommands.get(key));
}
小結
- reids提供multi exec/discard指令,類似open commit/rollback transaction,不過exec遇到型別操作等錯誤時不會滾,該成功執行的命令還是成功執行,該失敗的還是失敗
- multi exec保證的是,只要exec命令有執行成功,則事務中一系列的命令都能執行,如果exec因為網路等問題,server端沒有接收到,則事務中的一系列命令都不會被執行
- discard需要在有呼叫multi的前提下才能使用,該命令會清空事務佇列等待執行的命令
- redis提供watch指令,可以配合multi exec來使用,可以實現類似資料庫的樂觀鎖的機制,一旦watch的key被其他client有更新,則整個exec操作失敗