Redis事务



什么是redis事务

Redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令,当调用了EXEC命令将执行所有命令。
Redis中,单条命令是原子性执行的,但Redis事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。

Redis事务常用方法、

multi():开启事务
watch(String... keys):监听key是否被修改,如果在执行exec()前被修改则取消事务
unwatch():取消监听
exec():将事务需要执行的命令发送给Redis执行,并返回结果。返回结果是一个按命令执行顺序返回的list,
discard():取消事务

注意:Redis事务和管道一样,都是异步模式。在事务开启未执行前无法获取到查询操作的结果,必须等待执行exec()后才能获取到结果

小知识点 junit中的@Before@After注解

@Before:被@After修饰的方法在@Test方法执行前执行

@After:被@After修饰的方法在@Test方法执行后执行

demo测试

测试时的公共方法和Jedis对象

static final Jedis jedis = RedisSimplePool.getJedis();
/**
 * 清空数据库
 */
@Before
public void flushdb() {
	jedis.select(0); //切换数据库
	System.out.println("清空数据库");
	jedis.flushDB();
}

/**
 * 
 * @描述:返还连接
 * @作者:严磊
 * @时间:2020年6月17日 下午10:27:02
 */
@After
public void closeConn() {
	RedisSimplePool.returnJedis(jedis);
}

1、开启事务并提交

/**
 * 
 * @描述:测试开启事务并提交
 * @作者:严磊
 * @时间:2020年6月17日 下午9:10:33
 */
@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("*"));
}


执行结果:
transaction.exec();处加入断点。
执行exec方法前,数据库没有数据。
执行exec方法后,数据库插入了4个key。
在这里插入图片描述


2、开启事务然后主动放弃事务

/**
 * 
 * @描述:测试开启事务然后主动放弃事务
 * @作者:严磊
 * @时间:2020年6月17日 下午9:11:30
 */
@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("*"));
}


3、使用watch监听指定的键是否被修改,如果在执行exec前被修改则取消事务

/**
 * 
 * @描述:watch 命令会标记一个或多个键,如果事务中被标记的键,在提交事务之前被修改了,那么提交事务,事务就会失败。
 * @作者:严磊
 * @时间:2020年6月17日 下午9:12:25
 * @throws InterruptedException
 */
@Test
public void watchTest() throws InterruptedException {
	//boolean resultValue = transMethod(200);
	boolean resultValue = transMethod(10);
	System.out.println("交易结果(事务执行结果):" + resultValue);
	
	int balance = Integer.parseInt(jedis.get("balance"));
	int debt = Integer.parseInt(jedis.get("expense"));
	
	System.out.printf("balance: %d, expense: %d\n", balance, debt);
}

// 支付操作
public static boolean transMethod(int amtToSubtract) throws InterruptedException {
	int balance;  // 余额
	int expense;  // 已消费额
	
	jedis.set("balance", "100");
	jedis.set("expense", "0");
	
	jedis.watch("balance", "expense");
	
	balance = Integer.parseInt(jedis.get("balance"));
	
	// 余额不足
	if (balance < amtToSubtract) {
		jedis.unwatch();  // 放弃所有被监控的键
		System.out.println("余额不足");
		return false;
	}
	
	Transaction transaction = jedis.multi();
	// 扣钱
	transaction.decrBy("balance", amtToSubtract);
	Thread.sleep(15000);  // 在外部修改 balance 或者 expense
	transaction.incrBy("expense", amtToSubtract);
	
	// list为空说明事务执行失败
	List<Object> list = transaction.exec();
	
	if(list==null)
	{
		return false;
	}
	else
	{
		list.forEach(System.out::println);
		return true;
	}
}

执行结果:
如果在事务执行exec方法前,对key balanceexpense进行了修改,exec()方法会返回null。事务中的命令都不会执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值