Last active
July 10, 2017 08:28
-
-
Save JunqiangYang/b15816c4a4e5d1d1c8abfb4687a7dba6 to your computer and use it in GitHub Desktop.
redis cache
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class JsonSerializer<V> implements ObjectSerializer<String, V> { | |
@Override | |
public String serialize(V value) { | |
return JsonUtil.toJson(value); | |
} | |
@SuppressWarnings("unchecked") | |
@Override | |
public V deseralize(String bs, Class<?> clz) { | |
return (V) JsonUtil.fromJson(bs, clz); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* K-List缓存定义 | |
* @author easezhang | |
* | |
* 2015年11月5日 | |
* @param <K> Key类型 | |
* @param <V> List存放对象类型 | |
*/ | |
public interface KListCache<K, V> { | |
public List<V> get(K key); | |
public void del(K key); | |
public int size(K key); | |
public Page<V> getPage(K key, int pageNo, int pageSize); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* KV缓存 | |
* @author easezhang | |
* 无需提供set方法,只要发现数据变更调用del方法即可 | |
* | |
* 2015年11月6日 | |
* @param <K> Key类型 | |
* @param <V> Value类型 | |
*/ | |
public interface KVCache<K, V> { | |
/** | |
* 获取key对应的value,内置absent的获取逻辑 | |
* @param key | |
* @return | |
*/ | |
public V get(K key); | |
/** | |
* 删除key对应的value,当数据有更新的时候调用的方法 | |
* @param key | |
* @return 0 成功 其他:失败 | |
*/ | |
public int del(K key); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.List; | |
import java.util.Map; | |
/** | |
* 在KVCache之上增加了批量get,批量del接口 | |
* @author easezhang | |
* | |
* 2015年12月11日 | |
* @param <K> | |
* @param <V> | |
*/ | |
public interface KVCacheEx<K, V> extends KVCache<K, V> { | |
/** | |
* 批量获取多个key对应的value | |
* @param keys | |
* @return | |
*/ | |
public Map<K, V> multiGets(List<K> keys); | |
/** | |
* 批量删除多个key | |
* @param keys | |
*/ | |
public void multiDels(List<K> keys); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 在KVCache之上增加了批量set,get接口 | |
* @param <K> | |
* @param <V> | |
*/ | |
public interface KVCacheSimple<K, V> extends KVCache<K, V> { | |
/** | |
* 简单的插入一条记录 | |
* @param key | |
* @param v | |
*/ | |
public void set(K key,V v); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.List; | |
import com.nyonline.sp2p.client.RedisClient; | |
import com.nyonline.util.BizLogger; | |
import com.nyonline.util.StringUtil; | |
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
public class NumKVCacheEx { | |
private final String cacheName; | |
private final int expireSec; | |
private final String keyPrefix; | |
public NumKVCacheEx(String cacheName, int expireSec, String keyPrefix) { | |
this.cacheName = cacheName; | |
this.expireSec = expireSec; | |
this.keyPrefix = keyPrefix; | |
} | |
private String key(String k) { | |
return keyPrefix+k; | |
} | |
public long get(String key, long def) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String v = jedis.get(key(key)); | |
if(StringUtil.isEmpty(v)) { | |
return def; | |
} | |
return StringUtil.convertLong(v, def); | |
} | |
catch(JedisConnectionException e) { | |
BizLogger.error(e, "broken"); | |
broken = true; | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return def; | |
} | |
public Long change(String key, long delta, long def) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
Pipeline p = jedis.pipelined(); | |
p.incrBy(key(key), delta); | |
p.expire(key(key), this.expireSec); | |
List<Object> list = p.syncAndReturnAll(); | |
if(list.size() > 0) { | |
return StringUtil.convertLong(String.valueOf(list.get(0)), def); | |
} | |
} | |
catch(JedisConnectionException e) { | |
BizLogger.error(e, "broken"); | |
broken = true; | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return null; | |
} | |
public static void main(String ...args) { | |
NumKVCacheEx cache = new NumKVCacheEx("iplimit", 43200, "ipl"); | |
System.out.println(cache.get("123.124.20.250", 0)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 对象序列化生成器 | |
* @author easezhang | |
* | |
* 2015年11月5日 | |
* @param <S> 序列化后的类型 | |
* @param <V> 原始值类型 | |
*/ | |
public interface ObjectSerializer<S, V> { | |
public S serialize(V value); | |
public V deseralize(S bs, Class<?> clz); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.protobuf.GeneratedMessage; | |
/** | |
* protobuf序列器 | |
* @author easezhang | |
* | |
* 2015年12月11日 | |
* @param <V> | |
*/ | |
public abstract class PbSerializer<V extends GeneratedMessage> implements ObjectSerializer<byte[], V> { | |
@Override | |
public byte[] serialize(V value) { | |
return value.toByteArray(); | |
} | |
@Override | |
public abstract V deseralize(byte[] bs, Class<?> clz); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
/** | |
* redis存放kv的缓存,key用string类型,value用v类型 | |
* @author easezhang | |
* | |
* 2015年12月11日 | |
* @param <V> | |
*/ | |
public class RedisJsonKVCache<V> implements KVCache<String, V> { | |
protected ObjectSerializer<String, V> valueSerializer; | |
protected final Class<V> clz; | |
protected final String cacheName; | |
protected final int expireSec; | |
public RedisJsonKVCache(ObjectSerializer<String, V> valueSerializer, Class<V> clz, | |
String cacheName, int expireSec) { | |
super(); | |
this.valueSerializer = valueSerializer; | |
this.clz = clz; | |
this.cacheName = cacheName; | |
this.expireSec = expireSec; | |
} | |
private void setValue(Jedis jedis, java.lang.String key, java.lang.String value) { | |
Pipeline p = jedis.pipelined(); | |
p.set(key, value); | |
p.expire(key, this.expireSec); | |
p.sync(); | |
} | |
@Override | |
public V get(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String value = jedis.get(key); | |
if(StringUtil.isEmpty(value)) { | |
V v = onAbsent(key); | |
if(v!=null) { | |
value = valueSerializer.serialize(v); | |
setValue(jedis, key, value); | |
} | |
return v; | |
} | |
else { | |
return valueSerializer.deseralize(value, this.clz); | |
} | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return null; | |
} | |
@Override | |
public int del(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
jedis.del(key); | |
return ReturnValue.OK; | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return ReturnValue.REDIS_ERR; | |
} | |
/** | |
* 当value不存在时候,从哪里可以获取到value,子类需重载 | |
* @param key | |
* @return | |
*/ | |
protected V onAbsent(String key) { | |
throw new UnsupportedOperationException(); | |
} | |
public final String getPrefix() { | |
return AppConfig.get("redis."+this.cacheName+".keyprefix", ""); | |
} | |
public static void main(String ...args) { | |
RedisJsonKVCache<String> cache = new RedisJsonKVCache<String>(new StringSerializer(), String.class, "userbankcard", 1000) { | |
@Override | |
protected String onAbsent(String key) { | |
return "hi"; | |
} | |
}; | |
System.out.println(cache.get("1")); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
public class RedisJsonKVCacheEx<V> extends RedisJsonKVCache<V> implements KVCacheEx<String, V>{ | |
public RedisJsonKVCacheEx(ObjectSerializer<String, V> valueSerializer, Class<V> clz, String cacheName, | |
int expireSec) { | |
super(valueSerializer, clz, cacheName, expireSec); | |
} | |
private static String [] getKeys(List<String> keys) { | |
String [] strs = new String[keys.size()]; | |
return keys.toArray(strs); | |
} | |
private void mset(String [] kvs, Jedis jedis) { | |
Pipeline p = jedis.pipelined(); | |
jedis.mset(kvs); | |
for(int i=0;i<kvs.length;i+=2) { | |
jedis.expire(kvs[i], this.expireSec); | |
} | |
p.sync(); | |
} | |
public Map<String, V> multiGets(List<String> keys) { | |
Jedis jedis = null; | |
Map<String, V> map = new HashMap<String, V>(); | |
if(Utils.isEmpty(keys)) { | |
return map; | |
} | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
List<String> strs = jedis.mget(getKeys(keys)); | |
V detail = null; | |
for(String str : strs) { | |
if(!StringUtil.isEmpty(str)) { | |
detail = JsonUtil.fromJson(str, this.clz); | |
map.put(key(detail), detail); | |
} | |
} | |
List<String> absentBids = new ArrayList<String>(); | |
for(String key : keys) { | |
if(map.get(key) == null) { | |
absentBids.add(key); | |
} | |
} | |
if(absentBids.isEmpty()) return map; | |
Map<String, V> absentDetails = this.onAbsents(absentBids); | |
if(Utils.isEmpty(absentDetails)) return map; | |
map.putAll(absentDetails); | |
String [] kvs = new String[absentDetails.size()*2]; | |
int index = 0; | |
for(String key: absentDetails.keySet()) { | |
kvs[index++] = key; | |
kvs[index++] = JsonUtil.toJson(absentDetails.get(key)); | |
} | |
mset(kvs, jedis); | |
} | |
catch(JedisConnectionException e) { | |
BizLogger.error(e, "broken"); | |
broken = true; | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return map; | |
} | |
protected String key(V v) { | |
throw new UnsupportedOperationException(); | |
} | |
protected Map<String, V> onAbsents(List<String> keys) { | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public void multiDels(List<String> keys) { | |
Jedis jedis = null; | |
if(Utils.isEmpty(keys)) { | |
return ; | |
} | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
Pipeline p = jedis.pipelined(); | |
String [] tmpKeys = new String[keys.size()]; | |
tmpKeys = keys.toArray(tmpKeys); | |
BizLogger.info("del keys", Arrays.toString(tmpKeys)); | |
p.del(tmpKeys); | |
p.sync(); | |
} | |
catch(JedisConnectionException e) { | |
BizLogger.error(e, "broken"); | |
broken = true; | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
} | |
public static void main(String ...args) { | |
ArrayList<String> s = new ArrayList<String>(); | |
s.add("1"); | |
s.add("2"); | |
String [] tmps = new String[s.size()]; | |
String [] k = s.toArray(tmps); | |
System.out.println(Arrays.toString(k)+"|"+Arrays.toString(tmps)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Arrays; | |
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
public class RedisJsonKVCacheSimple<V> extends RedisJsonKVCache<V> implements KVCacheSimple<String, V>{ | |
public RedisJsonKVCacheSimple(ObjectSerializer<String, V> valueSerializer, Class<V> clz, String cacheName, | |
int expireSec) { | |
super(valueSerializer, clz, cacheName, expireSec); | |
} | |
@Override | |
public void set(String key, V v) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String value = valueSerializer.serialize(v); | |
setValue(jedis, key, value); | |
} catch (JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} catch (Throwable th) { | |
BizLogger.error(th); | |
} finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
} | |
@Override | |
public V get(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String value = jedis.get(key); | |
if (!StringUtil.isEmpty(value)) { | |
return valueSerializer.deseralize(value, this.clz); | |
} | |
} catch (JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} catch (Throwable th) { | |
BizLogger.error(th); | |
} finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return null; | |
} | |
private void setValue(Jedis jedis, java.lang.String key, java.lang.String value) { | |
Pipeline p = jedis.pipelined(); | |
p.set(key, value); | |
p.expire(key, this.expireSec); | |
p.sync(); | |
} | |
public static void main(String ...args) { | |
ArrayList<String> s = new ArrayList<String>(); | |
s.add("1"); | |
s.add("2"); | |
String [] tmps = new String[s.size()]; | |
String [] k = s.toArray(tmps); | |
System.out.println(Arrays.toString(k)+"|"+Arrays.toString(tmps)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.List; | |
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.Response; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
public class RedisKJsonListCache<V> implements KListCache<String, V>{ | |
private final ObjectSerializer<String, V> valueSerializer; | |
private final Class<V> clz; | |
private final String cacheName; | |
private final int expretSec; | |
/** | |
* 缓存构造 | |
* @param valueSerializer value序列者 | |
* @param keySerializer key序列者 | |
* @param clz value对应的class | |
* @param cacheName 缓存名称,配置在redis.config | |
* @param expireSec 过期秒数 | |
*/ | |
public RedisKJsonListCache( Class<V> clz, String cacheName, int expireSec) { | |
this.valueSerializer = new JsonSerializer<V>(); | |
this.clz = clz; | |
this.cacheName = cacheName; | |
this.expretSec = expireSec; | |
} | |
private List<String> serialize(List<V> list) { | |
if(Utils.isEmpty(list)) return new ArrayList<String>(0); | |
List<String> retList = new ArrayList<String>(list.size()); | |
for(V v:list) { | |
retList.add(valueSerializer.serialize(v)); | |
} | |
return retList; | |
} | |
private List<V> deserialize(List<String> list) { | |
if(Utils.isEmpty(list)) return new ArrayList<V>(0); | |
List<V> retList = new ArrayList<V>(list.size()); | |
for(String v:list) { | |
retList.add(valueSerializer.deseralize(v, clz)); | |
} | |
return retList; | |
} | |
private void setValue(Jedis jedis, String bkey, String[]value) { | |
Pipeline p = jedis.pipelined(); | |
p.del(bkey); | |
p.rpush(bkey, value); | |
p.expire(bkey, this.expretSec); | |
p.sync(); | |
} | |
@Override | |
public List<V> get(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
List<V> retList = new ArrayList<V>(0); | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String bkey = key; | |
long len = jedis.llen(bkey); | |
List<String> list = jedis.lrange(bkey, 0, len-1); | |
if(Utils.isEmpty(list)) { | |
retList = this.onAbsent(key); | |
list = serialize(retList); | |
if(!Utils.isEmpty(list)) { | |
String [] strs = new String[list.size()]; | |
list.toArray(strs); | |
setValue(jedis, bkey, strs); | |
} | |
} | |
else { | |
retList = deserialize(list); | |
} | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return retList; | |
} | |
@Override | |
public void del(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
jedis.del(key); | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
} | |
@Override | |
public int size(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
long size = jedis.llen(key); | |
if(size > 0) return (int)size; | |
else { | |
List<V> list = this.get(key); | |
return list.size(); | |
} | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return 0; | |
} | |
@Override | |
public Page<V> getPage(String key, int pageNo, int pageSize) { | |
Jedis jedis = null; | |
boolean broken = false; | |
List<V> retList = new ArrayList<V>(pageSize); | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String bkey = key; | |
Pipeline p = jedis.pipelined(); | |
Response<Long> len = p.llen(bkey); | |
Response<List<String>> list = p.lrange(bkey, (pageNo-1)*pageSize, pageNo*pageSize-1); | |
p.sync(); | |
long total = len.get(); | |
if(total > 0) { | |
retList = deserialize(list.get()); | |
} | |
else { | |
List<V> allList = this.onAbsent(key); | |
total = allList.size(); | |
if(!Utils.isEmpty(allList)) { | |
String [] strs = new String[allList.size()]; | |
int index = 0; | |
for(V v:allList) { | |
strs[index++] = valueSerializer.serialize(v); | |
} | |
setValue(jedis, bkey, strs); | |
} | |
retList.addAll(allList.subList(Math.min((pageNo-1)*pageSize, allList.size()), Math.min(pageNo*pageSize, allList.size()))); | |
} | |
return new Page<V>(retList, (int)total, pageNo, pageSize); | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return new Page<V>(retList, 0, pageNo, pageSize); | |
} | |
/** | |
* 当key在缓存不存在的时候,从持久介质获取,禁止返回空 | |
* @param key | |
* @return | |
*/ | |
protected List<V> onAbsent(String key) { | |
return new ArrayList<V>(0); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.List; | |
import com.google.protobuf.GeneratedMessage; | |
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.Response; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
/** | |
* Redis Key-List<V> 类型缓存<br/> | |
* List里的数据不建议太多<br/> | |
* V采用pb进行序列化和反序列化 <br/> | |
* 无需提供set方法,只要发现数据变更调用del方法即可,适用于带着数据持久化功能的缓存 | |
* @author easezhang | |
* | |
* 2015年11月5日 | |
* @param <K> | |
* @param <V> | |
*/ | |
public class RedisKListCache<K, V extends GeneratedMessage> implements KListCache<K, V> { | |
private final PbSerializer<V> valueSerializer; | |
private final SimpleSerializer keySerializer; | |
private final Class<V> clz; | |
private final String cacheName; | |
private final int expretSec; | |
/** | |
* 缓存构造 | |
* @param valueSerializer value序列者 | |
* @param keySerializer key序列者 | |
* @param clz value对应的class | |
* @param cacheName 缓存名称,配置在redis.config | |
* @param expireSec 过期秒数 | |
*/ | |
public RedisKListCache(PbSerializer<V> valueSerializer, SimpleSerializer keySerializer, Class<V> clz, String cacheName, int expireSec) { | |
this.valueSerializer = valueSerializer; | |
this.keySerializer = keySerializer; | |
this.clz = clz; | |
this.cacheName = cacheName; | |
this.expretSec = expireSec; | |
} | |
private List<byte[]> serialize(List<V> list) { | |
if(Utils.isEmpty(list)) return new ArrayList<byte[]>(0); | |
List<byte[]> retList = new ArrayList<byte[]>(list.size()); | |
for(V v:list) { | |
retList.add(valueSerializer.serialize(v)); | |
} | |
return retList; | |
} | |
private List<V> deserialize(List<byte[]> list) { | |
if(Utils.isEmpty(list)) return new ArrayList<V>(0); | |
List<V> retList = new ArrayList<V>(list.size()); | |
for(byte[] v:list) { | |
retList.add(valueSerializer.deseralize(v, clz)); | |
} | |
return retList; | |
} | |
private void setValue(Jedis jedis, byte[] bkey, byte[][]value) { | |
Pipeline p = jedis.pipelined(); | |
p.del(bkey); | |
p.rpush(bkey, value); | |
p.expire(bkey, this.expretSec); | |
p.sync(); | |
} | |
@Override | |
public List<V> get(K key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
List<V> retList = new ArrayList<V>(0); | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
byte[] bkey = keySerializer.serialize(key); | |
long len = jedis.llen(bkey); | |
List<byte[]> list = jedis.lrange(bkey, 0, len-1); | |
if(Utils.isEmpty(list)) { | |
retList = this.onAbsent(key); | |
list = serialize(retList); | |
if(!Utils.isEmpty(list)) { | |
setValue(jedis, bkey, Utils.asBytesArray(list)); | |
} | |
} | |
else { | |
retList = deserialize(list); | |
} | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return retList; | |
} | |
@Override | |
public void del(K key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
byte[] bkey = keySerializer.serialize(key); | |
jedis.del(bkey); | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
} | |
@Override | |
public int size(K key) { | |
List<V> list = this.get(key); | |
return list.size(); | |
} | |
@Override | |
public Page<V> getPage(K key, int pageNo, int pageSize) { | |
Jedis jedis = null; | |
boolean broken = false; | |
List<V> retList = new ArrayList<V>(pageSize); | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
byte[] bkey = keySerializer.serialize(key); | |
Pipeline p = jedis.pipelined(); | |
Response<Long> len = p.llen(bkey); | |
Response<List<byte[]>> list = p.lrange(bkey, (pageNo-1)*pageSize, pageNo*pageSize-1); | |
p.sync(); | |
long total = len.get(); | |
if(total > 0) { | |
retList = deserialize(list.get()); | |
} | |
else { | |
List<V> allList = this.onAbsent(key); | |
total = allList.size(); | |
if(!Utils.isEmpty(allList)) { | |
setValue(jedis, bkey, Utils.asBytesArray(serialize(allList))); | |
} | |
retList.addAll(allList.subList(Math.min((pageNo-1)*pageSize, allList.size()), Math.min(pageNo*pageSize, allList.size()))); | |
} | |
return new Page<V>(retList, (int)total, pageNo, pageSize); | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return new Page<V>(retList, 0, pageNo, pageSize); | |
} | |
/** | |
* 当key在缓存不存在的时候,从持久介质获取,禁止返回空 | |
* @param key | |
* @return | |
*/ | |
protected List<V> onAbsent(K key) { | |
return new ArrayList<V>(0); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.protobuf.GeneratedMessage; | |
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
public class RedisKVCache<K, V extends GeneratedMessage> implements KVCache<K, V> { | |
private final PbSerializer<V> valueSerializer; | |
private final SimpleSerializer keySerializer; | |
private final Class<V> clz; | |
private final String cacheName; | |
private final int expireSec; | |
public RedisKVCache(PbSerializer<V> valueSerializer, SimpleSerializer keySerializer, Class<V> clz, | |
String cacheName, int expireSec) { | |
this.valueSerializer = valueSerializer; | |
this.keySerializer = keySerializer; | |
this.clz = clz; | |
this.cacheName = cacheName; | |
this.expireSec = expireSec; | |
} | |
private void setValue(Jedis jedis, byte[] bkey, byte[]value) { | |
Pipeline p = jedis.pipelined(); | |
p.set(bkey, value); | |
p.expire(bkey, this.expireSec); | |
p.sync(); | |
} | |
@Override | |
public V get(K key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
byte[] bkey = keySerializer.serialize(key); | |
byte[] value = jedis.get(bkey); | |
if(value == null || value.length == 0) { | |
V v = onAbsent(key); | |
if(v!=null) { | |
value = valueSerializer.serialize(v); | |
setValue(jedis, bkey, value); | |
} | |
return v; | |
} | |
else { | |
return valueSerializer.deseralize(value, this.clz); | |
} | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return null; | |
} | |
@Override | |
public int del(K key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
byte[] bkey = keySerializer.serialize(key); | |
jedis.del(bkey); | |
return ReturnValue.OK; | |
} | |
catch(JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} | |
catch(Throwable th) { | |
BizLogger.error(th); | |
} | |
finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return ReturnValue.REDIS_ERR; | |
} | |
protected V onAbsent(K key) { | |
throw new UnsupportedOperationException(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.List; | |
import org.apache.commons.lang3.StringUtils; | |
import redis.clients.jedis.Jedis; | |
import redis.clients.jedis.Pipeline; | |
import redis.clients.jedis.Response; | |
import redis.clients.jedis.exceptions.JedisConnectionException; | |
public class SimpleRedisKJsonListCache<V> { | |
private final ObjectSerializer<String, V> valueSerializer; | |
private final Class<V> clz; | |
private final String cacheName; | |
private final int expretSec; | |
public SimpleRedisKJsonListCache(Class<V> clz, String cacheName, int expireSec) { | |
this.valueSerializer = new JsonSerializer<V>(); | |
this.clz = clz; | |
this.cacheName = cacheName; | |
this.expretSec = expireSec; | |
} | |
private List<String> serialize(List<V> list) { | |
if (Utils.isEmpty(list)) | |
return new ArrayList<String>(0); | |
List<String> retList = new ArrayList<String>(list.size()); | |
for (V v : list) { | |
retList.add(valueSerializer.serialize(v)); | |
} | |
return retList; | |
} | |
private List<V> deserialize(List<String> list) { | |
if (Utils.isEmpty(list)) | |
return new ArrayList<V>(0); | |
List<V> retList = new ArrayList<V>(list.size()); | |
for (String v : list) { | |
retList.add(valueSerializer.deseralize(v, clz)); | |
} | |
return retList; | |
} | |
private V deserialize(String v) { | |
return valueSerializer.deseralize(v, clz); | |
} | |
private void addValue(Jedis jedis, String bkey, String[] value) { | |
Pipeline p = jedis.pipelined(); | |
p.rpush(bkey, value); | |
p.sync(); | |
} | |
public void add(String key, V v) { | |
List<V> list = new ArrayList<V>(1); | |
list.add(v); | |
addByList(key, list); | |
} | |
public void addByList(String key, List<V> valueList) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String bkey = key; | |
List<String> list = new ArrayList<String>(); | |
list = serialize(valueList); | |
if (!Utils.isEmpty(list)) { | |
String[] strs = new String[list.size()]; | |
list.toArray(strs); | |
addValue(jedis, bkey, strs); | |
} | |
} catch (JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} catch (Throwable th) { | |
BizLogger.error(th); | |
} finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
} | |
public V popHead(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String bkey = key; | |
Pipeline p = jedis.pipelined(); | |
Response<String> valueRs = p.lpop(bkey); | |
p.sync(); | |
String value = valueRs.get(); | |
if (!StringUtils.isEmpty(value)) { | |
return deserialize(value); | |
} | |
} catch (JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} catch (Throwable th) { | |
BizLogger.error(th); | |
} finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return null; | |
} | |
public Page<V> getPage(String key, int pageNo, int pageSize) { | |
Jedis jedis = null; | |
boolean broken = false; | |
List<V> retList = new ArrayList<V>(pageSize); | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
String bkey = key; | |
Pipeline p = jedis.pipelined(); | |
Response<Long> len = p.llen(bkey); | |
Response<List<String>> list = p.lrange(bkey, (pageNo - 1) * pageSize, pageNo * pageSize - 1); | |
p.sync(); | |
long total = len.get(); | |
if (total > 0) { | |
retList = deserialize(list.get()); | |
} | |
return new Page<V>(retList, (int) total, pageNo, pageSize); | |
} catch (JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} catch (Throwable th) { | |
BizLogger.error(th); | |
} finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
return new Page<V>(retList, 0, pageNo, pageSize); | |
} | |
public void del(String key) { | |
Jedis jedis = null; | |
boolean broken = false; | |
try { | |
jedis = RedisClient.getInstance(this.cacheName); | |
jedis.del(key); | |
} catch (JedisConnectionException e) { | |
broken = true; | |
BizLogger.error(e); | |
} catch (Throwable th) { | |
BizLogger.error(th); | |
} finally { | |
RedisClient.returnInstance(this.cacheName, jedis, broken); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.nyonline.util.StringUtil; | |
public class SimpleSerializer implements ObjectSerializer<byte[], Object> { | |
@Override | |
public byte[] serialize(Object value) { | |
return StringUtil.toUtf8Bytes(String.valueOf(value)); | |
} | |
@Override | |
public Object deseralize(byte[] bs, Class<?> clz) { | |
return StringUtil.fromUtf8Bytes(bs); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class StringSerializer implements ObjectSerializer<String, String> { | |
@Override | |
public String serialize(String value) { | |
return value; | |
} | |
@Override | |
public String deseralize(String bs, Class<?> clz) { | |
return bs; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment