C# 内存缓存工具类 MemoryCacheUtil
C# 内存缓存工具类 MemoryCacheUtil

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Timers; namespace Utils
{
/// <summary>
/// 缓存
/// 缓存数据存储在内存中
/// 适用于CS项目,BS项目慎用
/// </summary>
public static class MemoryCacheUtil
{
#region 变量
/// <summary>
/// 内存缓存
/// </summary>
private static ConcurrentDictionary<string, CacheData> _cacheDict = new ConcurrentDictionary<string, CacheData>(); /// <summary>
/// 对不同的键提供不同的锁,用于读缓存
/// </summary>
private static ConcurrentDictionary<string, string> _dictLocksForReadCache = new ConcurrentDictionary<string, string>(); /// <summary>
/// 过期缓存检测Timer
/// </summary>
private static Timer _timerCheckCache;
#endregion #region 静态构造函数
static MemoryCacheUtil()
{
_timerCheckCache = new Timer();
_timerCheckCache.Interval = 60 * 1000;
_timerCheckCache.Elapsed += _timerCheckCache_Elapsed;
_timerCheckCache.Start();
}
#endregion #region 获取并缓存数据
/// <summary>
/// 获取并缓存数据
/// 高并发的情况建议使用此重载函数,防止重复写入内存缓存
/// </summary>
/// <param name="cacheKey">键</param>
/// <param name="func">在此方法中初始化数据</param>
/// <param name="expirationSeconds">缓存过期时间(秒),0表示永不过期</param>
/// <param name="refreshCache">立即刷新缓存</param>
public static T TryGetValue<T>(string cacheKey, Func<T> func, int expirationSeconds = 0, bool refreshCache = false)
{
lock (_dictLocksForReadCache.GetOrAdd(cacheKey, cacheKey))
{
object cacheValue = MemoryCacheUtil.GetValue(cacheKey);
if (cacheValue != null && !refreshCache)
{
return (T)cacheValue;
}
else
{
T value = func();
MemoryCacheUtil.SetValue(cacheKey, value, expirationSeconds);
return value;
}
}
}
#endregion #region SetValue 保存键值对
/// <summary>
/// 保存键值对
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="value">值</param>
/// <param name="expirationSeconds">过期时间(秒),0表示永不过期</param>
internal static void SetValue(string key, object value, int expirationSeconds = 0)
{
try
{
CacheData data = new CacheData(key, value);
data.updateTime = DateTime.Now;
data.expirationSeconds = expirationSeconds; CacheData temp;
_cacheDict.TryRemove(key, out temp);
_cacheDict.TryAdd(key, data);
}
catch (Exception ex)
{
LogUtil.Error(ex, "MemoryCacheUtil写缓存错误");
}
}
#endregion #region GetValue 获取键值对
/// <summary>
/// 获取键值对
/// </summary>
internal static object GetValue(string key)
{
try
{
CacheData data;
if (_cacheDict.TryGetValue(key, out data))
{
if (data.expirationSeconds > 0 && DateTime.Now.Subtract(data.updateTime).TotalSeconds > data.expirationSeconds)
{
CacheData temp;
_cacheDict.TryRemove(key, out temp);
return null;
}
return data.value;
}
return null;
}
catch (Exception ex)
{
LogUtil.Error(ex, "MemoryCacheUtil读缓存错误");
return null;
}
}
#endregion #region Delete 删除缓存
/// <summary>
/// 删除缓存
/// </summary>
internal static void Delete(string key)
{
CacheData temp;
_cacheDict.TryRemove(key, out temp);
}
#endregion #region DeleteAll 删除全部缓存
/// <summary>
/// 删除全部缓存
/// </summary>
internal static void DeleteAll()
{
_cacheDict.Clear();
}
#endregion #region 过期缓存检测
/// <summary>
/// 过期缓存检测
/// </summary>
private static void _timerCheckCache_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Task.Run(() =>
{
try
{
foreach (string cacheKey in _cacheDict.Keys.ToList())
{
CacheData data;
if (_cacheDict.TryGetValue(cacheKey, out data))
{
if (data.expirationSeconds > 0 && DateTime.Now.Subtract(data.updateTime).TotalSeconds > data.expirationSeconds)
{
CacheData temp;
string strTemp;
_cacheDict.TryRemove(cacheKey, out temp);
_dictLocksForReadCache.TryRemove(cacheKey, out strTemp);
}
}
}
}
catch (Exception ex)
{
LogUtil.Error(ex, "过期缓存检测出错");
}
});
}
#endregion }
}
为什么BS项目慎用?因为IIS会回收进程,所以需要注意一下。
为什么过期缓存检测遍历代码是foreach (string cacheKey in _cacheDict.Keys.ToList()),要使用ToList()?_cacheDict.Keys不是线程安全的,防止并发异常。
为什么加锁的代码是lock (_dictLocksForReadCache.GetOrAdd(cacheKey, cacheKey))?为了支持多线程并发,防止重复进入func函数。
CacheData类:

/// <summary>
/// 缓存数据
/// </summary>
[Serializable]
public class CacheData
{
/// <summary>
/// 键
/// </summary>
public string key { get; set; }
/// <summary>
/// 值
/// </summary>
public object value { get; set; }
/// <summary>
/// 缓存更新时间
/// </summary>
public DateTime updateTime { get; set; }
/// <summary>
/// 过期时间(秒),0表示永不过期
/// </summary>
public int expirationSeconds { get; set; } /// <summary>
/// 缓存数据
/// </summary>
/// <param name="key">缓存键</param>
/// <param name="value">值</param>
public CacheData(string key, object value)
{
this.key = key;
this.value = value;
}
}
如何使用:

private void button2_Click(object sender, EventArgs e)
{
List<string> list = MemoryCacheUtil.TryGetValue<List<string>>("cacheKey001", () =>
{
return QueryData();
});
} /// <summary>
/// 模拟从数据库查询数据
/// </summary>
private List<string> QueryData()
{
List<string> result = new List<string>(); for (int i = 0; i < 10; i++)
{
result.Add(i.ToString());
} return result;
}
多线程并发测试:

private void TestMemoryCache()
{
Log("开始");
for (int i = 0; i < 5; i++)
{
Task.Run(() =>
{
string str1 = MemoryCacheUtil.TryGetValue<string>("1", () =>
{
Thread.Sleep(2000);
Log("取数据1");
return "1";
});
Log(str1);
}); Task.Run(() =>
{
string str2 = MemoryCacheUtil.TryGetValue<string>("2", () =>
{
Thread.Sleep(2000);
Log("取数据2");
return "2";
});
Log(str2);
}); Task.Run(() =>
{
string str3 = MemoryCacheUtil.TryGetValue<string>("3", () =>
{
Thread.Sleep(2000);
Log("取数据3");
return "3";
});
Log(str3);
});
}
}
C# 内存缓存工具类 MemoryCacheUtil的更多相关文章
- 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; usi ...
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
Go/Python/Erlang编程语言对比分析及示例 本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...
- Cache【硬盘缓存工具类(包含内存缓存LruCache和磁盘缓存DiskLruCache)】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 内存缓存LruCache和磁盘缓存DiskLruCache的封装类,主要用于图片缓存. 效果图 代码分析 内存缓存LruCache和 ...
- php 缓存工具类 实现网页缓存
php 缓存工具类 实现网页缓存 php程序在抵抗大流量访问的时候动态网站往往都是难以招架,所以要引入缓存机制,一般情况下有两种类型缓存 一.文件缓存 二.数据查询结果缓存,使用内存来实现高速缓存 本 ...
- thrift之TTransport层的内存缓存传输类TMemoryBuffer
内存缓存是简单的在内存进行读写操作的一种传输,任何时候想在上面写入数据都是放入缓存中,任何时候读操作数据也是来至于缓存.内存缓存的分配使用c语言的malloc类函数,分配的长度是需要长度的两倍,需要考 ...
- redis缓存工具类
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis ...
- redis缓存工具类,提供序列化接口
1.序列化工具类 package com.qicheshetuan.backend.util; import java.io.ByteArrayInputStream; import java.io. ...
- CookieUtils-浏览器缓存工具类
package cn.yonyong.myproject.commons.utils; import javax.servlet.http.Cookie; import javax.servlet.h ...
- 缓存工具类CacheHelper
代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...
- 基于spring的redisTemplate的缓存工具类
pom.xml文件添加 <!-- config redis data and client jar --><dependency> <groupId>org.spr ...
随机推荐
- PVE 下虚拟机 Ubuntu 无法进入恢复模式的解决方案——提取原有系统文件
问题说明 某天重启虚拟机 Ubuntu,发现虚拟机只有容器IP,桥接的接口在虚拟机显示状态为 DOWN: 想重启进入恢复模式,却发现恢复模式一直花屏,无法使用: 没有办法了,只能想办法提取原有系统内原 ...
- Ubuntu下使用apt-get命令查询并安装指定版本的软件
执行以下命令,查询软件所有的版本号 sudo apt-cache madison <package> <package>为需要安装的包名,返回结果第二列即可用的版本号 执行以下 ...
- 什么是RPC协议
工作的时候,第一次接触CRPC协议,当时就很懵,啥是CRPC协议,一脸懵逼,于是就到网上去搜,填充知识空缺. 不少解释显得非常官方,我相信大家在各种平台上也都看到过,解释了又好像没解释,都在用一个我们 ...
- 终结篇:==和equals有什么区别?
== 和 equals 有什么区别?这个问题本身不难,但是被问到的频率很高,且大部分人的回答都不够全面,让人听了有种"恨铁不成钢"的感觉,所以今天咱们就来好好聊聊这个问题. 1.典 ...
- Illegal overloaded getter method with ambiguous type for property......
问题原因 建议 1.boolean类型的属性值不建议设置为is开头,否则会引起rpc框架的序列化异常. 2.如果强行将IDE自动生成的isSuccess()方法修改成getSuccess(),也能获取 ...
- Mybatis-Flex核心功能之@Table
1.能干啥? @Table 主要是用于给 Entity 实体类添加标识,用于描述 实体类 和 数据库表 的关系,以及对实体类进行的一些 功能辅助. 例如: 数据库有一张tb_member的会员表 这时 ...
- mysql 定时 数据库备份并上传到另一台服务器上,上传结束并删除源文件
首先总共有两个脚本: #!/bin/bash:主要用于进行数据库备份.压缩.删除,单独运行命令是:bash XXX.sh #!/usr/bin/expect:主要用于进行数据备份文件的上传,单独运行 ...
- python tkinter使用(五)
python tkinter使用(五) 本篇文章讲述tkinter 中treeview的使用 Treeview是一个多列列表框,可以显示层次数据. #!/usr/bin/python3 # -*- c ...
- Python——第五章:json模块
什么是json: json 模块是用于处理 JSON(JavaScript Object Notation)数据的模块,翻译过来叫js对象简谱.JSON是一种轻量级的数据交换格式,常用于将数据在不同语 ...
- C语言编程需要掌握的核心要点有哪些? 编程大神为你总结了这20个
摘要:C语言作为编程的入门语言,学习者如何快速掌握其核心知识点,面对茫茫书海,似乎有点迷茫.为了让各位快速地掌握C语言的知识内容,在这里对相关的知识点进行了归纳. 引言 笔者有十余年的C++开发经验, ...