生成一个唯一的缓存键基于方法参数 [英] Generating a unique cache key based on method arguments
问题描述
我有一个最终执行查询,并将结果映射回一个对象,一个基本的仓库框架:
I have a basic repository framework that eventually executes a query and maps the results back into a object:
例如:
public SomeEntity Get(id)
{
return base.GetItem<SomeEntity>
("select * from SomeEntities where id = @idParam",
new { idParam = id});
}
如果这看起来像小巧玲珑,那是因为引擎盖下的GetItem的包装小巧精致。
If this looks like Dapper, it is because under the hood GetItem is wrapping Dapper.
我想自动缓存增加的GetItem,我有一个有两个参数:
I'd like to add automatic caching to GetItem, I have two arguments that come in:
- 包含查询字符串。
- 包含任何参数的匿名字典。
我很担心,做一个简单的黄金散列这些参数会导致缓存键冲突,当您从缓存中提取数据,冲突可能是非常非常糟糕(IE浏览器泄露敏感 信息)。
I'm worried that doing a simple prime hash on these parameters would cause cache key collisions, and when you are pulling data from a cache, a collision can be very very bad (I.E. leaking sensitive information).
那么,做什么技术我有一个会产生一个合理规模的缓存键,同时保证基于查询和参数的输入独特性?
So, what techniques do I have that would generate a reasonably sized cache key, while guaranteeing uniqueness based on the input of a query and parameters?
推荐答案
我用下面的扩展方法,使代表缓存版本:
I use the following extension methods to make cached versions of delegates:
public static Func<T, TResult> AsCached<T, TResult>(this Func<T, TResult> function)
{
var cachedResults = new Dictionary<T, TResult>();
return (argument) =>
{
TResult result;
lock (cachedResults)
{
if (!cachedResults.TryGetValue(argument, out result))
{
result = function(argument);
cachedResults.Add(argument, result);
}
}
return result;
};
}
public static Func<T1, T2, TResult> AsCached<T1, T2, TResult>(this Func<T1, T2, TResult> function)
{
var cachedResults = new Dictionary<Tuple<T1, T2>, TResult>();
return (value1, value2) =>
{
TResult result;
var paramsTuple = new Tuple<T1, T2>(value1, value2);
lock(cachedResults)
{
if (!cachedResults.TryGetValue(paramsTuple, out result))
{
result = function(value1, value2);
cachedResults.Add(paramsTuple, result);
}
}
return result;
};
}
public static Func<T1, T2, T3, TResult> AsCached<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> function)
{
var cachedResults = new Dictionary<Tuple<T1, T2, T3>, TResult>();
return (value1, value2, value3) =>
{
TResult result;
var paramsTuple = new Tuple<T1, T2, T3>(value1, value2, value3);
lock(cachedResults)
{
if (!cachedResults.TryGetValue(paramsTuple, out result))
{
result = function(value1, value2, value3);
cachedResults.Add(paramsTuple, result);
}
}
return result;
};
}
等了N个参数...
And so on for N parameters...
在情况下,它不会从code清楚,我创建一个参数的元组,并使用元组作为一个关键的字典持有的返回值各组参数。请注意,每次调用 AsCached
时,就创建一个单独的缓存。
In case it's not clear from the code, I create a tuple with the arguments, and use the tuple as a key to a dictionary that holds the return values for each set of arguments. Note that every time you call AsCached
, you create a separate cache.
您可以使用这些方法如下:
You can use these methods as follows:
private Func<int, SomeEntity> _getCached;
public SomeEntity Get(int id)
{
if (_getCached == null)
{
Func<int, SomeEntity> func = GetImpl;
_getCached = func.AsCached();
}
return _getCached(id);
}
private SomeEntity GetImpl(int id)
{
return base.GetItem<SomeEntity>
("select * from SomeEntities where id = @idParam",
new { idParam = id});
}
这篇关于生成一个唯一的缓存键基于方法参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!