Я хочу использовать этот паттерн:
SqlCommand com = new SqlCommand(sql, con);
com.CommandType = CommandType.StoredProcedure;//um
com.CommandTimeout = 120;
//com.Connection = con; //EDIT: per suggestions below
SqlParameter par;
par = new SqlParameter("@id", SqlDbType.Int);
par.Direction = ParameterDirection.Input;
com.Parameters.Add(par);
HttpContext.Current.Cache["mycommand"] = com;
Очевидно, я не хочу сталкиваться со странными проблемами, такими как человек A, извлекающий это из кеша, обновляющий param1, человек 2, получающий его из кеша и обновляющий param2, и каждый пользователь, выполняющий команду со смесью двух.
И клонирование команды, взятой из кеша, вероятно, дороже, чем создание новой команды с нуля.
Насколько потокобезопасен кэш ASP.NET? Не упускаю ли я других потенциальных ловушек? Будет ли этот метод работать для команд без параметров, несмотря на проблемы с потоками?
Осветление: Если я хочу образно прострелить себе ногу, как мне прицелиться? Есть ли способ заблокировать доступ к объектам в кеше, чтобы доступ был сериализован?





Сам кэш является потокобезопасным, но это не обеспечивает потокобезопасность размещаемым в нем объектам. Объект SqlCommand не является потокобезопасным и, следовательно, не из тех вещей, которые вы хотели бы кэшировать.
Самым важным в этом сценарии является кеширование соединения, которое выполняется за вас, и вы не должны пытаться следить за этим самостоятельно.
Создание объекта команды (даже со многими параметрами) все равно будет мелочью по сравнению с его выполнением. Если у вас нет доказательств для контра, не пытайтесь их кэшировать.
Самый большой риск для вашего проекта - преждевременная оптимизация.
Очень просто: не надо. Если вы не видите, что это неправильно, вам нужно больше узнать об ADO.NET. Существует множество литературы, в которой объясняется, как это правильно делать: просто создавайте соединения и команды, когда они вам нужны, и убедитесь, что вы их правильно разместили.
Как утверждали другие, это просто плохая идея. Это плохая идея по ряду причин.
Более того, если вы находитесь в ситуации высокой нагрузки, сохранение команды для каждого пользователя действительно быстро заполнит кеш и, в зависимости от приоритетов и т. д., Начнет вызывать выпадение других элементов из кеша. , это ДЕЙСТВИТЕЛЬНО должно быть там.
В ADO.NET вы действительно должны создавать, использовать, а затем удалять свои команды и соединения по мере их использования. Что касается производительности, мне НИКОГДА не приходилось менять эту систему ... и я не слышал о многих других, которые тоже меняли.
Кроме того, как другие упоминали в вашем примере кода, соединение, которое необходимо для фактического выполнения, все равно будет потеряно.
Зачем вам вообще кэшировать команда? Накладные расходы на создание команды незначительны - вы просто создаете новую пару объектов и устанавливаете некоторые свойства. Я никогда не видел, чтобы это было узким местом ..
Вы хотите кэшировать полученные результаты команды, так как на самом деле выполнение команда (относительно) дорогая. И, в общем, вы хотите обрабатывать общий кеш как доступный только для чтения, чтобы вам не приходилось беспокоиться о блокировке и синхронизации доступа. Кэширование результатов позволяет добиться этого.
Кэшируйте свои результаты и создавайте соединение (и команду) только в том случае, если кэш результатов равен нулю:
PsuedoCode:
result = getResultFromCache(CacheKey)
if (result == null)
{
result = getResultFromDB();
InsertIntoCache(result,cacheKey);
}
return result;
Мне следовало спросить, как заблокировать элемент в кеше ASP.NET, вместо того, чтобы говорить, что я собирался поместить в кеш.
lock(Cache)
{
// do something with cache that otherwise wouldn't be threadsafe
}
Ссылка: http://www.codeguru.com/csharp/.net/net_asp/article.php/c5363
IMHO лучшее решение, чем в связанной статье, - это поместить поточно-безопасный объект в кеш: это может быть поточно-ориентированная оболочка для объекта, который не является поточно-ориентированным.