【Redis】在實際Java項目中使用Redis的幾個關鍵步驟

【此爲原創文章,轉載必須先徵得本人同意且註明出處。】

一、Redis基礎學習

參考:Redis教程

二、RedisTemplate的應用

參考:Spring中使用RedisTemplate操作Redis

三、項目中的關鍵操作

假設我需要存儲用戶的真實信息,並且對認證次數有限制:最多可認證3次,3次還未通過時,該賬號不可再進行實名認證操作。
於是我需要用到redis來存儲此用戶認證失敗的次數,並且需要一個狀態標誌來分別存儲認證失敗時的value認證次數以及認證成功時的value真實信息,並且在用戶在規定次數限制內認證成功時移除掉用戶認證失敗的Cache(如果有的話)

1.產生key

以uid與verifyState爲key
單獨建一個用來存儲key的類RedisConstant

public static final String REDIS_KEY_REAL_INFO_VERIFY = "user:%s:verify_state:%s";
private String genRealInfoVerifyKey(Long uid, Byte verifyState) {
    return String.format(RedisConstant.REDIS_KEY_REAL_INFO_VERIFY, uid, verifyState);
}

認證失敗,則值爲0的verifyState與uid一起作爲key。
認證成功,則值爲1的verifyState與uid一起作爲key。

2.增加Cache

//認證成功
addRealInfoVerifyCache(uid, RealInfoVerifyStateEnum.Verify_Success.value(), realInfo, null);
//認證失敗
Integer verifiedNum = 0;
addRealInfoVerifyCache(uid, RealInfoVerifyStateEnum.Verify_Failure.value(), null, verifiedNum);
String key = genRealInfoVerifyKey(uid, verifyState);
redisCache.incr(key, 1);//將verifiedNum增1

private void addRealInfoVerifyCache(Long uid, Byte verifyState, RealInfo realInfo, Integer verifiedNum){
    if (RealInfoVerifyStateEnum.Verify_Success.equals(verifyState)){
        redisCache.putCache(genRealInfoVerifyKey(uid, verifyState), realInfo);
    }else if (RealInfoVerifyStateEnum.Verify_Failure.equals(verifyState)){
        redisCache.set(genRealInfoVerifyKey(uid, verifyState), verifiedNum.toString());
    }
}

認證失敗,則verifiedNum(失敗次數)爲value。verifiedNum爲整數。
認證成功,則realInfo(真實信息)爲value。realInfo爲實體類。

set操作與putCache操作的不同
set
適用於value爲字符串的情況

public void set(String key, String value) {
    redisTemplate.opsForValue().set(key, value);
}

putCache
適用於value爲實體類的情況,對類進行序列化操作來進行存儲

public <T> boolean putCache(String key, T obj) {
    final byte[] bKey = key.getBytes();
    final byte[] bValue = ProtoStuffSerializerUtil.serialize(obj);
    boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
        @Override
        public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
            return connection.setNX(bKey, bValue);
        }
    });
    return result;
}

3.獲取Cache

普通字符串

//獲取認證失敗的次數
String key = genRealInfoVerifyKey(uid, RealInfoVerifyStateEnum.Verify_Failure.value());
String verifiedNumStr = redisCache.get(key);

利用反序列化取類

//獲取用戶真實信息
String key = genRealInfoVerifyKey(uid, RealInfoVerifyStateEnum.Verify_Success.value());
RealInfo realInfo = redisCache.getCache(key, RealInfo.class);

redisCache.getCache

public <T> T getCache(final String key, Class<T> targetClass) {
    byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
        @Override
        public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
            return connection.get(key.getBytes());
        }
    });
    if (result == null) {
        return null;
    }
    return ProtoStuffSerializerUtil.deserialize(result, targetClass);
}

4.移除Cache

removeRealInfoVerifyCache(uid, RealInfoVerifyStateEnum.Verify_Failure.value());
removeRealInfoVerifyCache(uid, RealInfoVerifyStateEnum.Verify_Success.value());

private void removeRealInfoVerifyCache(Long uid, Byte verifyState){
    redisCache.deleteCache(genRealInfoVerifyKey(uid, verifyState));
}

四、其它補充

1.RedisCache封裝類

package com.component.cache;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qumitech.douqu.component.util.ProtoStuffSerializerUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redis緩存
 *
 * @author yingjun
 */
@Component("RedisCache")
public class RedisCache {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public void zAdd(String key, String value, double score) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        zset.add(key, value, score);
    }

    public Set<String> zRangeByScore(String key, double min, double max) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        return zset.rangeByScore(key, min, max);
    }

    public Double zIncrBy(String key, String value, double score) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        return zset.incrementScore(key, value, score);
    }

    public Long zCard(String key) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        return zset.zCard(key);
    }

    public void zRemRange(String key, long l1, long l2) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        zset.removeRange(key, l1, l2);
    }

    public Set<ZSetOperations.TypedTuple<String>> reverseRangeWithScores(String key, Long min, Long max) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        return zset.reverseRangeWithScores(key, min, max);
    }

    public Set<String> zRange(String key, Long min, Long max) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        return zset.range(key, min, max);
    }

    public Set<String> zReverseRange(String key, Long min, Long max) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        return zset.reverseRange(key, min, max);
    }

    public Set<ZSetOperations.TypedTuple<String>> zRangeWithScores(String key, Long min, Long max) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        return zset.rangeWithScores(key, min, max);
    }

    public void zRem(String key) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        //test:Zrem需要制定分數段查詢範圍
        Long i = zset.removeRangeByScore(key, 0, 99999999999999999L);
    }

    public void zRem(String key, String member) {
        ZSetOperations<String, String> zset = redisTemplate.opsForZSet();
        //test:Zrem需要制定分數段查詢範圍
        Long i = zset.remove(key, member);
    }

    public <T> boolean putCache(String key, T obj) {
        final byte[] bKey = key.getBytes();
        final byte[] bValue = ProtoStuffSerializerUtil.serialize(obj);
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.setNX(bKey, bValue);
            }
        });
        return result;
    }

    /**
     * @param key
     * @param obj
     * @param expireTime 單位: s
     * @param <T>
     */
    public <T> void putCacheWithExpireTime(String key, T obj, final long expireTime) {
        final byte[] bKey = key.getBytes();
        final byte[] bValue = ProtoStuffSerializerUtil.serialize(obj);
        redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.setEx(bKey, expireTime, bValue);
                return true;
            }
        });
    }

    public <T> boolean putListCache(String key, List<T> objList) {
        final byte[] bKey = key.getBytes();
        final byte[] bValue = ProtoStuffSerializerUtil.serializeList(objList);
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.setNX(bKey, bValue);
            }
        });
        return result;
    }

    public <T> boolean putListCacheWithExpireTime(String key, List<T> objList, final long expireTime) {
        final byte[] bKey = key.getBytes();
        final byte[] bValue = ProtoStuffSerializerUtil.serializeList(objList);
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.setEx(bKey, expireTime, bValue);
                return true;
            }
        });
        return result;
    }

    public <T> T getCache(final String key, Class<T> targetClass) {
        byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
            @Override
            public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.get(key.getBytes());
            }
        });
        if (result == null) {
            return null;
        }
        return ProtoStuffSerializerUtil.deserialize(result, targetClass);
    }

    public <T> List<T> getListCache(final String key, Class<T> targetClass) {
        byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
            @Override
            public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.get(key.getBytes());
            }
        });
        if (result == null) {
            return null;
        }
        return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
    }

    /**
     * 精確刪除key
     *
     * @param key
     */
    public void deleteCache(String key) {
        redisTemplate.delete(key);
    }

    /**
     * 模糊刪除key
     *
     * @param pattern
     */
    public void deleteCacheWithPattern(String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }

    /**
     * 遞增
     *
     * @param key   鍵
     * @param delta 需要增加幾
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞增因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 遞減
     *
     * @param key   鍵
     * @param delta 要減少幾
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞減因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    /**
     * 獲取字符串值
     *
     * @param key
     * @return
     */
    public String getString(String key, String defaultValue) {
        String value = redisTemplate.opsForValue().get(key);
        if (StringUtils.isEmpty(value)) {
            value = defaultValue;
        }
        return value;
    }

    public String getSet(String key, String value) {
        String valueOld = redisTemplate.opsForValue().getAndSet(key, value);
        ;
        if (StringUtils.isEmpty(valueOld)) {
            valueOld = "0";
        }
        return valueOld;
    }

    public String get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public <T> List<T> getList(String key, Class<T> targetClass) {
        String value = get(key);
        return JSONObject.parseArray(value, targetClass);
    }

    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public void setList(String key, List<?> objList) {
        String value = JSON.toJSONString(objList);
        set(key, value);
    }

    public boolean setnx(String key, String value) {
        return redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
                return redisConnection.setNX(key.getBytes(), value.getBytes());
            }
        });
    }

    public boolean setnxWithExpire(String key, String value, Integer expire) {
        return redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
                boolean result = false;
                if (redisConnection.setNX(key.getBytes(), value.getBytes())) {
                    result = redisConnection.expire(key.getBytes(), expire);
                }
                return result;
            }
        });
    }

    public void setExString(String key, String value, long l) {
        redisTemplate.opsForValue().set(key, value, l, TimeUnit.SECONDS);
    }

    /**
     * 設置緩存失效時間
     */
    public boolean expire(String key, Long time) {
        try {
            if (time != null && time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 往隊列裏添加數據
     *
     * @param key
     * @param value
     */
    public void lpush(String key, String value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    public String rpop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    public void lrem(String key, String val) {
        redisTemplate.opsForList().remove(key, 1, val);
    }

    public List<String> lrange(String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    public long lsize(String key) {
        return redisTemplate.opsForList().size(key);
    }

    public void sadd(String key, String... var2) {
        redisTemplate.opsForSet().add(key, var2);
    }

    public Set<String> smembers(String key) {

        return redisTemplate.<String>opsForSet().members(key);
    }

    public void hset(String key, String field, String value) {
        redisTemplate.opsForHash().put(key, field, value);
    }

    public String hget(String key, String field) {

        return redisTemplate.<String, String>opsForHash().get(key, field);
    }

    public Double zscore(String redisKey, String member) {

        return redisTemplate.<String, String>opsForZSet().score(redisKey, member);
    }

    public void zincrby(RedisKey redisKey, String member, double score) {
        String key = redisKey.getKeyStr();
        expire(key, redisKey.getExpireTime());
        redisTemplate.<String, String>opsForZSet().incrementScore(key, member, score);
    }

    public Set<String> getKeysByPattern(String pattern) {
        return redisTemplate.keys(pattern);
    }


    public Long getZsetReverseRank(String key, String member) {
        return redisTemplate.opsForZSet().reverseRank(key, member);
    }

    public Double getZsetScoreByMember(String key, String member) {
        return redisTemplate.opsForZSet().score(key, member);
    }

    public void rename(String oldKey, String newKey) {
        redisTemplate.rename(oldKey, newKey);
    }

    public Set<String> zRevrangeByScore(String key, Long minScore, Long maxScore) {
        return redisTemplate.opsForZSet().reverseRangeByScore(key, minScore, maxScore);
    }
}

2.序列化工具

package com.component.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;

/**
 * 序列話工具
 */
public class ProtoStuffSerializerUtil {

   /**
    * 序列化對象
    * @param obj
    * @return
    */
   public static <T> byte[] serialize(T obj) {
      if (obj == null) {
         throw new RuntimeException("序列化對象(" + obj + ")!");
      }
      @SuppressWarnings("unchecked")
      Schema<T> schema = (Schema<T>) RuntimeSchema.getSchema(obj.getClass());
      LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
      byte[] protostuff = null;
      try {
         protostuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
      } catch (Exception e) {
         throw new RuntimeException("序列化(" + obj.getClass() + ")對象(" + obj + ")發生異常!", e);
      } finally {
         buffer.clear();
      }
      return protostuff;
   }

   /**
    * 反序列化對象
    * @param paramArrayOfByte
    * @param targetClass
    * @return
    */
   public static <T> T deserialize(byte[] paramArrayOfByte, Class<T> targetClass) {
      if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
         throw new RuntimeException("反序列化對象發生異常,byte序列爲空!");
      }
      T instance = null;
      try {
         instance = targetClass.newInstance();
      } catch (InstantiationException | IllegalAccessException e) {
         throw new RuntimeException("反序列化過程中依據類型創建對象失敗!", e);
      }
      Schema<T> schema = RuntimeSchema.getSchema(targetClass);
      ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
      return instance;
   }

   /**
    * 序列化列表
    * @param objList
    * @return
    */
   public static <T> byte[] serializeList(List<T> objList) {
      if (objList == null || objList.isEmpty()) {
         throw new RuntimeException("序列化對象列表(" + objList + ")參數異常!");
      }
      @SuppressWarnings("unchecked")
      Schema<T> schema = (Schema<T>) RuntimeSchema.getSchema(objList.get(0).getClass());
      LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
      byte[] protostuff = null;
      ByteArrayOutputStream bos = null;
      try {
         bos = new ByteArrayOutputStream();
         ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);
         protostuff = bos.toByteArray();
      } catch (Exception e) {
         throw new RuntimeException("序列化對象列表(" + objList + ")發生異常!", e);
      } finally {
         buffer.clear();
         try {
            if (bos != null) {
               bos.close();
            }
         } catch (IOException e) {
            e.printStackTrace();
         }
      }

      return protostuff;
   }

   /**
    * 反序列化列表
    * @param paramArrayOfByte
    * @param targetClass
    * @return
    */
   public static <T> List<T> deserializeList(byte[] paramArrayOfByte, Class<T> targetClass) {
      if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
         throw new RuntimeException("反序列化對象發生異常,byte序列爲空!");
      }

      Schema<T> schema = RuntimeSchema.getSchema(targetClass);
      List<T> result = null;
      try {
         result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte), schema);
      } catch (IOException e) {
         throw new RuntimeException("反序列化對象列表發生異常!", e);
      }
      return result;
   }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章