cari

Rumah  >  Soal Jawab  >  teks badan

spring-data-redis - redis并发计数

说明:
用redis计数器存取用户的操作次数,最多3次,但是并发会超过3次,下面的代码对吗?

BoundValueOperations<String, String> operations = redisTemplate.boundValueOps("key1");
        String key1 = operations.get();
        if (StringUtils.isEmpty(key1)) {
            service.do();//这里是业务逻辑操作成功之后,计数器加1
            operations.increment(1);
        } else {
            if (Integer.parseInt(key1) < 2) {
                service.do();//这里是业务逻辑操作成功之后,计数器加1
                operations.increment(1);
            }
        }
phpcn_u1582phpcn_u15822797 hari yang lalu1132

membalas semua(2)saya akan balas

  • 世界只因有你

    世界只因有你2017-04-25 09:05:18

    Untuk perniagaan mengira seperti ini, anda perlu mengira dahulu dan kemudian baru berniaga. Jika perniagaan telah selesai dan kaunter didapati lebih besar daripada nilai had, anda akan terkejut.

    Pelan saya ialah:
    Disebabkan ketidakkonsistenan data yang disebabkan oleh konkurensi, anda boleh mempertimbangkan untuk menggunakan perintah INCR Redis untuk menambahnya sebanyak 1 dan mendapatkan nilai terkini (ini adalah operasi sekali sahaja, jadi ia tidak akan menyebabkan tidak konsisten):

    • Jika lebih daripada 3, bermakna ia telah melebihi dan sudah tamat; Jika

    • kurang daripada atau bersamaan dengan 3, laksanakan perniagaan sekali lagi (anda juga boleh mempertimbangkan kaunter balik untuk kegagalan pelaksanaan perniagaan).
    • balas
      0
  • ringa_lee

    ringa_lee2017-04-25 09:05:18

    Terdapat kelemahan tertentu dalam melaksanakan fungsi di atas melalui klien Java Dalam kes konkurensi tinggi, data mungkin tidak konsisten Adalah disyorkan untuk menggunakan skrip lua untuk merangkumkan keseluruhan logik untuk memastikan keatoman operasi. Anda boleh menggunakan SCRIPT LOAD ke Skrip dicache ke pelayan dan dilaksanakan melalui nilai semakan sha1 + parameter (Kunci, ARG) untuk mengurangkan penghantaran rangkaian

    Beri anda contoh:
    1 Keperluan fungsian: Jika kunci tidak wujud, tetapkannya dan kembalikan palsu, dan tetapkan tamat masa dan kiraan = 1 apabila tamat masa telah dicapai atau kiraan yang ditentukan tercapai, return false dan mulakan semula Tetapkan tamat masa dan kiraan=1; jika tamat masa tidak tercapai & kiraan yang ditentukan tidak tercapai, kembalikan benar dan kiraan incr

    Skrip redis.lua adalah seperti berikut:

    local key = KEYS[1];
    local expire = tonumber(KEYS[2]);
    local number = tonumber(KEYS[3]);
    local count = tonumber(redis.call("GET",key));
    if count == nil then
            redis.call("SETEX",KEYS[1],expire,"1");
            return false;
    else
            if count +1 >= number then;
                    redis.call("SETEX",KEYS[1],expire,"1");
                    return false;
            else
                    redis.call("INCR",KEYS[1]);
                    return true;
            end
    end
    

    Kod java adalah seperti berikut:

       public static final String REDIS_LUA = "redis.call('select',1);local key = KEYS[1];local expire = tonumber(KEYS[2]);" +
                "local number = tonumber(KEYS[3]);local count = tonumber(redis.call('GET',key));" +
                "if count == nil then redis.call('SETEX',KEYS[1],expire,'1');return 0;" +
                "else if count +1 >= number then redis.call('SETEX',KEYS[1],expire,'1');return 0;" +
                "else redis.call('INCR',KEYS[1]);return 1;end;end;";
        
        private static final String redisScript;
        
    
        static {
            try {
                Conf.load();
            } catch (Exception e) {
                e.printStackTrace();
            }
            jedisPool = new JedisPool(Conf.getRedisHost(), Conf.getRedisPort());
            redisScript = loadLuaScript();
        }
       private static String loadLuaScript() {
            Jedis jedis = null;
            String redisScript = null;
            try {
                jedis = jedisPool.getResource();
                redisScript = jedis.scriptLoad(REDIS_LUA);
            } catch (Exception e) {
                if (jedis != null) {
                    jedisPool.returnResource(jedis);
                }
            } finally {
                if (jedis != null) {
                    jedisPool.returnResource(jedis);
                }
            }
            return redisScript;
        }
        
        
      
    调用脚本
     Object result = jedis.evalsha(redisScript, ARGS_LENGTH
                        , key, expireTime, countVal);

    balas
    0
  • Batalbalas