zoukankan      html  css  js  c++  java
  • 基于Redis实现的抢购代码示例

    示例代码是基于博客 https://blog.csdn.net/qq1013598664/article/details/70183908的错误案例修改而来,如果有问题望多多指点,错误代码可以去原文查阅,本文将会指出错误之处。

    不多废话,直接上代码:

    package com.javartisan.concurrent;
    
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.List;
    import java.util.UUID;
    
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.Transaction;
    
    /**
     * redis并发抢购测试
     *
     * @author javartisan
     */
    public class RedisTest {
        public static void main(String[] args) {
            final String watchkeys = "watchkeys";
            ExecutorService executor = Executors.newFixedThreadPool(20);
    
            GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
    
            JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379, 10000, "root");
    
    
            final Jedis jedis = jedisPool.getResource();
            jedis.auth("root");
            jedis.set(watchkeys, "0");// 重置watchkeys为0
            jedis.del("setsucc", "setfail");// 清空抢成功的,与没有成功的
            jedis.close();
    
            for (int i = 0; i < 10000; i++) {// 测试一万人同时访问
                executor.execute(new MyRunnable(jedisPool));
            }
            executor.shutdown();
        }
    }
    
    
    class MyRunnable implements Runnable {
    
        String watchkeys = "watchkeys";// 监视keys
        JedisPool jedisPool = null;
    
    
        public MyRunnable(JedisPool jedisPool) {
            this.jedisPool = jedisPool;
        }
    
        @Override
        public void run() {
            Jedis jedis = jedisPool.getResource();
    
            try {
    
                jedis.watch(watchkeys);//代码块1 watchkeys
    
                String val = jedis.get(watchkeys);
                int valint = Integer.valueOf(val);
                String userifo = UUID.randomUUID().toString();
                if (valint < 10) {
    
                    Transaction tx = jedis.multi();//代码块2 开启事务
                    tx.incr("watchkeys");
                    List<Object> list = tx.exec();//代码块3 提交事务,如果此时watchkeys被改动了,则返回emptyList
    
                    if (list.size() > 0) {
                        System.out.println("用户:" + userifo + "抢购成功,当前抢购成功人数:" + (valint + 1));
                        /* 抢购成功业务逻辑 */
                        jedis.sadd("setsucc", userifo);
                        return;
                    }
                }
                System.out.println("用户:" + userifo + "抢购失败");
                jedis.sadd("setfail", userifo);
                return;
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                jedis.close();
            }
    
    
        }
    
    }
    

      

     

    原文错误之处在于对exec方法的处理,当事务被打断或者执行失败的话返回的是一个emptyList,并不是一个null,因此需要使用list.size判断事务状态。

    Jedis中的exec方法实现源码:

     public List<Object> exec() {
        client.exec();
        client.getAll(1); // Discard all but the last reply
        inTransaction = false;
    
        List<Object> unformatted = client.getObjectMultiBulkReply();
        if (unformatted == null) { //事务失败
          return Collections.emptyList();
        }
        List<Object> formatted = new ArrayList<Object>();
        for (Object o : unformatted) {
          try {
            formatted.add(generateResponse(o).get());
          } catch (JedisDataException e) {
            formatted.add(e);
          }
        }
        return formatted;
      }
    

      

    Redis抢购成功数据:

    抢购失败用户个数:

     备注说明:

    代码块1表示监督key,以准备执行事务,如果在事务执行期间该key对应的value被修改的话事务进行回滚。

    代码块2到代码块3之间是开启事务执行命令并提交事务,在这个代码期间必须使用事务对象执行命令,否者会报错。即使用tx操作。

    在事务中判断元素是否存在时候,返回的是一个Response对象,例如方法get:

    redis.clients.jedis.RedisPipeline#get

      public Response<String> get(String key) {
        getClient(key).get(key);
        return getResponse(BuilderFactory.STRING);
      }
    

    只能在事务执行完毕或者事务discard之后才可以get,不能再事务期间进行get。

    秒杀系统结合限流系统一起处理效果会更好

  • 相关阅读:
    java之day4补充
    java之day4
    JAVA之day3对象
    JAVA之DAY3
    JAVA之DAY2
    element-ui表格添加复选框及根据列表中的数据判断是否可选
    h5手机端上传多张图片(界面上的展示图片,删除图片)
    模态框-开启关闭事件
    Vue-粒子特效(vue-particles)
    网页常用代码片段-sessionStorage存储JSON
  • 原文地址:https://www.cnblogs.com/leodaxin/p/9553988.html
Copyright © 2011-2022 走看看