Windows下redis使用的两个问题:
1.本意我的key是存用户ID,value存token,但是接口上验证token,我得先判断token有没有,redis提供了根据键查找是否存 在,所以我只能把token存成key,但是token太长了,怕存成键有问题,可读性也差,关键时候登录服务器想根据用户ID看某个用户的token也 不方便找。想请教下大家这里怎么设计的?redis有没有提供了方法查是否存在某个value?我现在根据键查找代码:
public static bool KeyExists(string key, int db = -1) { try { using (var client = ConnectionMultiplexer.Connect(_conn)) { return Manager.GetDatabase(db).KeyExists(key); } } catch (Exception) { return false; } }
2.redis默认16个库,按照库存缓存已经搞出来了,如图:
但是一个库下,按照目录存缓存,始终没找到什么命令,看网友的这个图:
想请教大家这里用什么命令按照目录存缓存,dos命令或者C# RedisHelper都可以,麻烦知道的提供下思路
如果想按照目录存,在Key前加上前辍就可以,记得用冒号分开,如你想把一些键放到group这个目录下,就在Key前加上group:key,这样就可以
给你一个完整的RedisHelper
/// <summary> /// Redis类 /// </summary> public class CacheHelper { private static ConnectionMultiplexer RedisConnection; private static IDatabase Database; /// <summary> /// 静态构造函数 /// </summary> static CacheHelper() { if (CacheConfig.ConfigInfo.CacheEnable) { if (CacheHelper.RedisConnection == null) { CacheHelper.RedisConnection = ConnectionMultiplexer.Connect(string.Format("{0},connectTimeout=15000,syncTimeout=15000", CacheConfig.ConfigInfo.RedisAddress), null); } if (CacheHelper.Database == null) { CacheHelper.Database = CacheHelper.RedisConnection.GetDatabase(0, null); } } } /// <summary> /// 获取缓存值 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> public static T Get<T>(string key) { if (!CacheConfig.ConfigInfo.CacheEnable) { return default(T); } RedisValue redisValue = CacheHelper.Database.StringGet(CacheHelper.GetLocalizedKey(key), 0); if (string.IsNullOrEmpty(redisValue)) { return default(T); } return JsonConvert.DeserializeObject<T>(redisValue); } public static void Set<T>(string key, T value) { if (CacheConfig.ConfigInfo.CacheEnable) { string text = JsonConvert.SerializeObject(value); CacheHelper.Database.StringSet(CacheHelper.GetLocalizedKey(key), text, null, 0, 0); } } public static void Set<T>(string key, T value, TimeSpan validFor) { if (CacheConfig.ConfigInfo.CacheEnable) { string text = JsonConvert.SerializeObject(value); CacheHelper.Database.StringSet(CacheHelper.GetLocalizedKey(key), text, new TimeSpan?(validFor), 0, 0); } } public static void ListRightPush<T>(string key, T value) { if (CacheConfig.ConfigInfo.CacheEnable) { string text = JsonConvert.SerializeObject(value); CacheHelper.Database.ListRightPush(CacheHelper.GetLocalizedKey(key), text, 0, 0); } } public static T ListLeftPop<T>(string key) { if (!CacheConfig.ConfigInfo.CacheEnable) { return default(T); } RedisValue redisValue = CacheHelper.Database.ListLeftPop(CacheHelper.GetLocalizedKey(key), 0); if (string.IsNullOrEmpty(redisValue)) { return default(T); } return JsonConvert.DeserializeObject<T>(redisValue); } public static void Remove(string key) { if (CacheConfig.ConfigInfo.CacheEnable) { CacheHelper.Database.KeyDelete(CacheHelper.GetLocalizedKey(key), 0); } } public static void RemoveAll() { if (CacheConfig.ConfigInfo.CacheEnable) { CacheHelper.Database.KeyDeleteWithPrefix(CacheHelper.GetLocalizedKey("*")); } } private static string GetLocalizedKey(string key) { return CacheConfig.ConfigInfo.CachePrefix + key; } } public static class RedisDatabaseExtensions { public static void KeyDeleteWithPrefix(this IDatabase database, string prefix) { if (database == null) { throw new ArgumentException("Database cannot be null", "database"); } if (string.IsNullOrWhiteSpace(prefix)) { throw new ArgumentException("Prefix cannot be empty", "database"); } database.ScriptEvaluate(@" local keys = redis.call('keys', ARGV[1]) for i=1,#keys,5000 do redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) end", values: new RedisValue[] { prefix }); } public static int KeyCount(this IDatabase database, string prefix) { if (database == null) { throw new ArgumentException("Database cannot be null", "database"); } if (string.IsNullOrWhiteSpace(prefix)) { throw new ArgumentException("Prefix cannot be empty", "database"); } var retVal = database.ScriptEvaluate("return table.getn(redis.call('keys', ARGV[1]))", values: new RedisValue[] { prefix }); if (retVal.IsNull) { return 0; } return (int)retVal; } }
@韩天伟: 可以分目录了,感谢!但是另一个问题来了:目录下面的键都是以目录:键的形式存的,那么程序封装的时候就得给键签名拼上目录:要存的键,根据key读取的时候也要手动拼上目录:键 这样是常规做法么?
@心态要好: 一般不会每次手动拼,可以写个公用方法做这件事情,读取和写入时会用这个方法转换一下,把用哪个前辍来拼接时在这个方法里面判断
如:
private static string GetLocalizedKey(string key) { return CacheConfig.ConfigInfo.CachePrefix + key; }
@韩天伟: 感谢,很快解决了问题,悬赏全部给你。对了,兄弟是否可以分享下项目里怎么使用redis的?我现在是16个库,每个库对应服务器上的一个项目,一个项目里不同模块用到缓存用目录区分。
Key一般都有规则吧?
Key的规则一般根据项目自已掌握
@韩天伟: 这种直接把用户ID当key的就是坑.
@吴瑞祥: 每个项目或每个人用时都有他自已的规则,只要不重复就没什么问题,如果一个团队要做最好封装相应的方法,以免键重复或数据重复存储