事务
Redis 事务可以一次执行多个命令,有两个特性:
-
隔离性:事务的所有命令都会序列化、按顺序的执行,事务执行完后才会执行其他客服端的命令。
-
原子性: 事务中的命令要么全部被执行,要么全部不执行。
使用你事务时会遇到两个错误:
-
入队时出错,一般时因为语法错误引起的,加入事务队列就会报错,遇到这类错误,一般会放弃事务
-
EXEC调用后出错,列如对一个 值为
a1
的key
执行incr
,这类错误,即使某个命令产生了错误,其他命令依旧会继续执行执行,不会回滚
Reids 中的 WATCH
命令
使用 WATCH
命令可以监控键,如果被监控的键,再 EXEC
之前被修改,那么事务会放弃执行(注意:事务中的命令在 exec
命令后才开始执行)
EXEC
执行以后,无论事务是否执行成功,都会放弃对所有键的监控。
使用Java操控Redis事务命令
// 开启事务
Transaction transaction = jedis.multi();
// 提交事务
transaction.exec();
// 放弃事务
transaction.discard();
// 监控键
jedis.watch("balance", "debt");
// 放弃所有被监控的键
jedis.unwatch();
完整代码示例
package com.project.test;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
/**
* Rdis 事务
* @author wqj24
*
*/
public class TestTX {
static final Jedis jedis = new Jedis("132.232.6.208", 6381);
/**
* 清空数据库
*/
@Before
public void flushdb() {
jedis.flushDB();
}
@Test
public void commitTest() {
// 开启事务
Transaction transaction = jedis.multi();
transaction.set("key-1", "value-1");
transaction.set("key-2", "value-2");
transaction.set("key-3", "value-3");
transaction.set("key-4", "value-4");
// 提交事务
transaction.exec();
System.out.println(jedis.keys("*"));
}
@Test
public void discardTest() {
// 开启事务
Transaction transaction = jedis.multi();
transaction.set("key-1", "value-1");
transaction.set("key-2", "value-2");
transaction.set("key-3", "value-3");
transaction.set("key-4", "value-4");
// 放弃事务
transaction.discard();
System.out.println(jedis.keys("*"));
}
/**
* watch 命令会标记一个或多个键
* 如果事务中被标记的键,在提交事务之前被修改了,那么事务就会失败。
* @return
* @throws InterruptedException
*/
@Test
public void watchTest() throws InterruptedException {
boolean resultValue = transMethod(10);
System.out.println("交易结果(事务执行结果):" + resultValue);
int balance = Integer.parseInt(jedis.get("balance"));
int debt = Integer.parseInt(jedis.get("debt"));
System.out.printf("balance: %d, debt: %d\n", balance, debt);
}
// 支付操作
public static boolean transMethod(int amtToSubtract) throws InterruptedException {
int balance; // 余额
int debt; // 负债
jedis.set("balance", "100");
jedis.set("debt", "0");
jedis.watch("balance", "debt");
balance = Integer.parseInt(jedis.get("balance"));
// 余额不足
if (balance < amtToSubtract) {
jedis.unwatch(); // 放弃所有被监控的键
System.out.println("Insufficient balance");
return false;
}
Transaction transaction = jedis.multi();
// 扣钱
transaction.decrBy("balance", amtToSubtract);
Thread.sleep(5000); // 在外部修改 balance 或者 debt
transaction.incrBy("debt", amtToSubtract);
// list为空说明事务执行失败
List<Object> list = transaction.exec();
return !list.isEmpty();
}
}
网友评论