通过redis解决重复性请求(幂等性问题,附带样例代码)

1. 幂等性

幂等性的含义是一个用户对一个操作发起的一次或多次请求的结果是一致的。
下面是2个例子,创建订单和校验订单的时候,一段时间的请求的响应是一致的,并且只创建了一个订单。

2.创建订单

流程图:
在这里插入图片描述
样例代码:
Redis操作工具类:

public class RedissonUtil {

    private static RedissonUtil redissonUtil = new RedissonUtil();

    private static RedissonClient client = init();

    private RedissonUtil(){}

    private static RedissonClient init(){

        for(int i = 0; i < 3; i++){
            Config config = new Config();
            config.useSingleServer().setAddress("redis://107.150.98.45:7777")
                    .setPassword("morlia123")
                    .setConnectionMinimumIdleSize(10);
            try{
                RedissonClient client = Redisson.create(config);
                //不抛异常,就说明创建成功
                return client;
            }catch (Exception e){
                System.out.println(e);
            }
        }
        return null;
    }

    /**
     * 获取分布式锁,分布式锁的key值会自动加_lock后缀
     * @param key 原生key值
     * @param millis 超时时间,必选
     * @return 是否获取锁
     */
    public boolean getLock(String key, long millis){
        millis = millis <= 0 ? 2000:millis;
        String lockKey = key + "_lock";
        RBucket<String> keyObject = client.getBucket(lockKey);
        return keyObject.trySet(lockKey,millis, TimeUnit.MILLISECONDS);
    }

    /**
     * 释放掉lock锁
     * @param key 原始key值
     * @return 是否成功
     */
    public boolean releaseLock(String key){
        String lockKey = key + "_lock";
        RBucket<String> keyObject = client.getBucket(lockKey);
        return keyObject.delete();
    }

    public String getValue(String key){
        RBucket<String> keyObject = client.getBucket(key);
        return keyObject.get();
    }

    public void setValue(String key, String value, long millis){
        RBucket<String> keyObject = client.getBucket(key);
        keyObject.set(value, millis, TimeUnit.MILLISECONDS);
    }

    public boolean delValue(String key){
        RBucket<String> keyObject = client.getBucket(key);
        return keyObject.delete();
    }

    /**
     * 设置单例模式
     * 为了统一判定是否初始化成功
     * @return redissonUtil 对象
     */
    public static RedissonUtil getInstance(){
        //这边只是简单处理
        while(null == client){}
        return redissonUtil;
    }
}

创建订单流程主类

public static void main(String[] args){
     RedissonUtil util = RedissonUtil.getInstance();
     String createKey = "create_test_key";
     String createValue = "create_test_value";
     System.out.println("--------------------------------------创建流程开始------------------------------------------");
     //每300毫秒发送1次请求,模拟重复请求
     IntStream.range(0,10).forEach(i -> {
         new Thread(() ->{
             String value = util.getValue(createKey);
             if(null != value){
                 System.out.println("====================="
                         + Thread.currentThread().getName()
                         +"重复请求,直接返回结果:"
                         + value
                         + "============&#
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RocketMQ通过消息编号(Message ID)保证消息的幂等性,而Redis可以用来缓存已经消费过的消息编号,从而避免重复消费。 以下是一个使用RocketMQ和Redis实现幂等性的示例代码: ```java import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message; import redis.clients.jedis.Jedis; public class IdempotentDemo { private static final String TOPIC = "test_topic"; private static final String REDIS_KEY = "consumed_message_ids"; public static void main(String[] args) throws Exception { DefaultMQProducer producer = new DefaultMQProducer("producer_group"); producer.setNamesrvAddr("localhost:9876"); producer.start(); // 发送消息 Message message = new Message(TOPIC, "Hello world".getBytes()); message.setKeys("key1"); producer.send(message); // 模拟消费消息 String messageId = message.getKeys(); Jedis jedis = new Jedis("localhost", 6379); if (!jedis.sismember(REDIS_KEY, messageId)) { // 处理消息 System.out.println("Consuming message: " + message); // 缓存已消费的消息编号 jedis.sadd(REDIS_KEY, messageId); } else { System.out.println("Message already consumed: " + message); } producer.shutdown(); } } ``` 在这个示例中,我们首先创建了一个RocketMQ生产者,并向一个名为`test_topic`的主题发送了一条消息。然后我们模拟消费该消息,并使用Redis缓存已经消费过的消息编号。在每次消费消息时,我们首先检查该消息的编号是否存在于Redis缓存中,如果是,则说明该消息已经被消费过,否则我们处理该消息并将其编号添加到Redis缓存中。 需要注意的是,这个示例中使用了RocketMQ的Key属性作为消息编号,实际应用中可以根据具体情况选择其他方式来生成消息编号。另外,为了保证缓存的可靠性,我们还需要考虑Redis的持久化和高可用性等问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值