目录
什么是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 balance或expense进行了修改,exec()方法会返回null。事务中的命令都不会执行。
本文介绍了Redis事务,它能一次性、顺序性、排他性执行队列命令,但不保证原子性且无回滚。还提及了Redis事务常用方法,如开启、监听、取消等,同时介绍了JUnit注解小知识,并通过demo测试展示了开启事务提交、放弃事务及使用watch监听的执行结果。
2362

被折叠的 条评论
为什么被折叠?



