用于实现在一定时间内,只允许用户某个动作操作指定次数,超过次数就拒绝。
比如一分钟内每个用户只能访问某个页面10次。
✅ Jedis原子操作示例类AtomicOperationExample
类似速率限制器这类需求,需要使用redis来做原子操作。
AtomicOperationExample用来演示如何完成原子操作。
有2种方式: 事务和管道
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
import java.util.List;
/**
* Jedis原子操作示例类
* 演示Redis中的各种原子操作实现方式
*/
public class AtomicOperationExample {
/**
* 演示原子操作的方法
* @param jedis Jedis客户端实例
*/
public static void demonstrateAtomicOperations(Jedis jedis) {
System.out.println("\n----- 演示Jedis原子操作 -----\n");
// 清除可能存在的测试数据
jedis.del("counter", "user:1:balance", "user:2:balance", "transaction_test");
// 1. 使用事务(Transaction)示例
demonstrateTransactions(jedis);
// 2. 使用管道(Pipeline)示例
demonstratePipeline(jedis);
}
/**
* 演示使用Redis事务操作
*/
private static void demonstrateTransactions(Jedis jedis) {
System.out.println("【2. 事务操作示例】");
// 设置初始值
jedis.set("user:1:balance", "100");
jedis.set("user:2:balance", "50");
System.out.println("- 转账前 - 用户1余额: " + jedis.get("user:1:balance"));
System.out.println("- 转账前 - 用户2余额: " + jedis.get("user:2:balance"));
// 开始事务
Transaction tx = jedis.multi();
try {
// 执行事务中的命令
tx.decrBy("user:1:balance", 30); // 用户1减少30
tx.incrBy("user:2:balance", 30); // 用户2增加30
// 提交事务
List<Object> results = tx.exec();
System.out.println("- 事务执行成功: " + results);
} catch (Exception e) {
// 事务回滚
tx.discard();
System.out.println("- 事务执行失败,已回滚: " + e.getMessage());
}
// 查看转账后结果
System.out.println("- 转账后 - 用户1余额: " + jedis.get("user:1:balance"));
System.out.println("- 转账后 - 用户2余额: " + jedis.get("user:2:balance"));
System.out.println("\n结论:事务可以将多个命令作为一个原子单元执行,要么全部成功,要么全部失败。\n");
}
/**
* 演示使用Redis管道操作
*/
private static void demonstratePipeline(Jedis jedis) {
System.out.println("【3. 管道操作示例】");
// 开始管道
redis.clients.jedis.Pipeline pipeline = jedis.pipelined();
try {
// 添加多个命令到管道
for (int i = 0; i < 5; i++) {
pipeline.set("transaction_test:" + i, "value" + i);
pipeline.get("transaction_test:" + i);
}
// 执行管道中的所有命令
List<Object> results = pipeline.syncAndReturnAll();
System.out.println("- 管道执行结果数量: " + results.size());
System.out.println("- 第一个命令结果: " + results.get(0));
System.out.println("- 第二个命令结果: " + results.get(1));
} catch (Exception e) {
System.out.println("- 管道执行过程中发生异常: " + e.getMessage());
}
System.out.println("\n重要说明:");
System.out.println("1. 管道操作本身不保证原子性,即使添加了异常处理也不会改变这个特性");
System.out.println("2. 如果出现异常,部分命令可能已经执行成功,部分可能执行失败,数据可能不一致");
System.out.println("3. 管道的主要优势是减少网络往返次数,提高吞吐量");
System.out.println("4. 如果需要原子性保证,应使用事务或Lua脚本而不是管道\n");
System.out.println("结论:管道可以减少客户端与服务器之间的网络往返次数,提高执行效率,但不保证原子性。\n");
}
}
✅速率限制器
package com.foxbill.redisinaction.chapter8;
import redis.clients.jedis.Jedis;
import java.util.List;
/**
* @Description 速率限制器
*/
public class RateLimiter {
public static void start(Jedis jedis) {
long remainTimes = 0;
boolean isPermitted=false;
for (int i = 0; i < 10; i++) {
remainTimes = remainTimes(jedis);
System.out.println("remainTimes:"+remainTimes);
isPermitted = isPermitted(jedis);
System.out.println("isPermitted:"+isPermitted);
try {
//等待1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
/* 判断是否允许执行 */
public static boolean isPermitted(Jedis jedis) {
String key = "permit";
// 开始管道
redis.clients.jedis.Pipeline pipeline = jedis.pipelined();
pipeline.incr(key);
pipeline.expire(key, 60); //设置失效时间为60秒
// 执行管道中的所有命令
List<Object> results = pipeline.syncAndReturnAll();
Long incrResult = (Long)results.get(0); //第一个命令结果
int maxTimes = 10;
if (incrResult >= maxTimes) {
return false;
}else{
return true;
}
}
/*剩余时间*/
public static long remainTimes(Jedis jedis) {
int maxTimes = 10;
String key = "permit";
String s = jedis.get(key);
if (s == null) {
return maxTimes;
}
long currentTimes = Long.parseLong(s);
if (currentTimes >= maxTimes) {
return 0;
}
return maxTimes - currentTimes;
}
}
871

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



