Redis 事务详述,java 多并发面试题
注意禁止在 MULTI 和 EXEC 之间执行 WATCH 指令,这会导致 Redis 服务响应异常
2.6 UNWATCH
UNWATCH 用于取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。因为 EXEC 命令会执行事务,因此 WATCH 命令的效果已经产生了;而 DISCARD 命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 UNWATCH 了。
3、Jedis 使用事务
通过模拟一个简单的余额增加的例子,使用 Jedis 客户端来使用 Redis 的事务。
package?com.lizba.redis.tx;
import?redis.clients.jedis.Jedis;
import?redis.clients.jedis.Transaction;
import?java.math.BigDecimal;
import?java.util.List;
/**
*?<p>
*??????Redis 事务 demo
*?</p>
*?@Author:?Liziba
*?@Date:?2021/9/9?23:53
*/
public?class?TransactionDemo?{
private?Jedis?client;
public?TransactionDemo(Jedis?client)?{
this.client?=?client;
}
/**
*?添加余额
*?@param?userId????用户 id
*?@param?amt???????添加余额
*?@return
*/
public?BigDecimal?addBalance(String?userId,?BigDecimal?amt)?{
String?key?=?this.keyFormat(userId);
//?初始用户余额为 0
client.setnx(key,?"0");
while?(true)?{
client.watch(key);
BigDecimal?balance?=?new?BigDecimal(client.get(key)).setScale(2,?BigDecimal.ROUND_HALF_UP);
BigDecimal?amount?=?balance.add(amt);
Transaction?tx?=?client.multi();
tx.set(key,?amount.toPlainString());
List<Object>?exec?=?tx.exec(
);
//?返回值不为空则证明 Redis 事务成功
if?(exec?!=?null)?{
break;
}
}
return?new?BigDecimal(client.get(key)).setScale(2,?BigDecimal.ROUND_HALF_UP);
}
/**
*?获取总金额
*?@param?userId?用户 id
*?@return
*/
public?BigDecimal?getAmount(String?userId)?{
String?amt?=?client.get(keyFormat(userId));
return?new?BigDecimal(amt);
}
/**
*?Redis?key
*?@param?userId?用户 id
*?@return
*/
private?String?keyFormat(String?userId)?{
return?String.format("balance:%s",userId);
}
}
测试代码:
package?com.lizba.redis.tx;
import?redis.clients.jedis.Jedis;
import?java.math.BigDecimal;
import?java.util.concurrent.CountDownLatch;
/**
*?<p>
*??????测试 Redis 事务
*?</p>
*?@Author:?Liziba
*?@Date:?2021/9/10?0:03
*/
public?class?TestTransactionDemo?{
private?static?CountDownLatch?count?=?new?CountDownLatch(100);
public?static?void?main(String[]?args)?throws?InterruptedException?{
for?(int?i?=?0;?i?<?100;?i++)?{
new?Thread(()?->?{
Jedis?client?=?new?Jedis("192.168.211.109",?6379);
TransactionDemo?demo?=?new?TransactionDemo(client);
demo.addBalance("liziba",?BigDecimal.TEN);
client.close();
count.countDown();
}).start();
}
count.await();
Jedis?client?=?new?Jedis("192.168.211.109",?6379);
BigDecimal?amt?=?new?TransactionDemo(client).getAmount("liziba");
System.out.println(amt.toPlainString());
}
评论