using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
using System.Threading.Tasks; namespace AutoLogisticsPH.Common.Utils
{
/// <summary>
/// 基于MemoryCache(内存缓存)的缓存工具类
/// Author:左文俊
/// Date:2017/12/11
/// </summary>
public static class MemoryCacheUtil
{
private static readonly Object _locker = new object(), _locker2 = new object(); /// <summary>
/// 取缓存项,如果不存在则返回空
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public static T GetCacheItem<T>(String key)
{
try
{
return (T)MemoryCache.Default[key];
}
catch
{
return default(T);
}
} /// <summary>
/// 是否包含指定键的缓存项
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static bool Contains(string key)
{
return MemoryCache.Default.Contains(key);
} /// <summary>
/// 取缓存项,如果不存在则新增缓存项
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="cachePopulate"></param>
/// <param name="slidingExpiration"></param>
/// <param name="absoluteExpiration"></param>
/// <returns></returns>
public static T GetOrAddCacheItem<T>(String key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
{
if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
if (slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided"); if (MemoryCache.Default[key] == null)
{
lock (_locker)
{
if (MemoryCache.Default[key] == null)
{
T cacheValue = cachePopulate();
if (!typeof(T).IsValueType && ((object)cacheValue) == null) //如果是引用类型且为NULL则不存缓存
{
return cacheValue;
} var item = new CacheItem(key, cacheValue);
var policy = CreatePolicy(slidingExpiration, absoluteExpiration); MemoryCache.Default.Add(item, policy);
}
}
} return (T)MemoryCache.Default[key];
} /// <summary>
/// 取缓存项,如果不存在则新增缓存项
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="cachePopulate"></param>
/// <param name="dependencyFilePath"></param>
/// <returns></returns>
public static T GetOrAddCacheItem<T>(String key, Func<T> cachePopulate, string dependencyFilePath)
{
if (String.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
if (cachePopulate == null) throw new ArgumentNullException("cachePopulate"); if (MemoryCache.Default[key] == null)
{
lock (_locker2)
{
if (MemoryCache.Default[key] == null)
{
T cacheValue = cachePopulate();
if (!typeof(T).IsValueType && ((object)cacheValue) == null) //如果是引用类型且为NULL则不存缓存
{
return cacheValue;
} var item = new CacheItem(key, cacheValue);
var policy = CreatePolicy(dependencyFilePath); MemoryCache.Default.Add(item, policy);
}
}
} return (T)MemoryCache.Default[key];
} /// <summary>
/// 移除指定键的缓存项
/// </summary>
/// <param name="key"></param>
public static void RemoveCacheItem(string key)
{
try
{
MemoryCache.Default.Remove(key);
}
catch
{ }
} private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
{
var policy = new CacheItemPolicy(); if (absoluteExpiration.HasValue)
{
policy.AbsoluteExpiration = absoluteExpiration.Value;
}
else if (slidingExpiration.HasValue)
{
policy.SlidingExpiration = slidingExpiration.Value;
} policy.Priority = CacheItemPriority.Default; return policy;
} private static CacheItemPolicy CreatePolicy(string filePath)
{
CacheItemPolicy policy = new CacheItemPolicy();
policy.ChangeMonitors.Add(new HostFileChangeMonitor(new List<string>() { filePath }));
policy.Priority = CacheItemPriority.Default;
return policy;
}
}
}

支持:可指定绝对过期时间、滑动过期明间、文件依赖  三种缓存方式,目前已在公司各种生产业务项目中有使用。优点是可以根据数据的使用频率设置缓存有效期,特别是文件依赖缓存,比如:连接字符串读取一次后,若CONFIG文件没有改变,则缓存永久有效,一旦CONFIG更改,则缓存失效需重新读取,保证数据缓存的最大可用性,减少不必要的多次重复读取CONFIG。

使用示例很简单:(如下:会在第一次读取连接字符串并解密后返回给connstr变量,后续直接通过缓存KEY dbConnName直接返回连接字符串的结果,若修改了连接字符串的CONFIG文件,则缓存的项会失效,会重新读取连接字符串并重新加入到缓存中)
            string connstr= MemoryCacheUtil.GetOrAddCacheItem(dbConnName, () =>
            {
                var connStrSettings = ConfigUtil.GetConnectionString(dbConnName,dbConnectionStringConfigPath);
                string dbProdName = connStrSettings.ProviderName;
                string dbConnStr = connStrSettings.ConnectionString;
                return EncryptUtil.Decrypt(dbConnStr);
            }, "缓存依赖文件路路,如:c:\app\app.config");

分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!的更多相关文章

  1. Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    Go/Python/Erlang编程语言对比分析及示例   本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...

  2. 基于AQS实现的Java并发工具类

    本文主要介绍一下基于AQS实现的Java并发工具类的作用,然后简单谈一下该工具类的实现原理.其实都是AQS的相关知识,只不过在AQS上包装了一下而已.本文也是基于您在有AQS的相关知识基础上,进行讲解 ...

  3. Android分享到微信和朋友圈的工具类

    1.只要填写上正确的app_id,且引用上该工具类你就能实现分享到朋友圈和分享到微信. 2.需要到微信平台下载jar包,以及注册一个appid import android.content.Conte ...

  4. 基于Druid数据库连接池的DBUtil工具类

    工具类 DruidUtil.java package com.zzuli.util; import com.alibaba.druid.pool.DruidDataSourceFactory; imp ...

  5. 分享自己配置的HttpURLConnection请求数据工具类

    >>该工具类传入string类型url返回string类型获取结果import java.io.BufferedReader;import java.io.InputStream;impo ...

  6. AntZipUtils【基于Ant的Zip压缩解压缩工具类】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 Android 压缩解压zip文件一般分为两种方式: 基于JDK的Zip压缩工具类 该版本存在问题:压缩时如果目录或文件名含有中文, ...

  7. 基于WebImage的图片上传工具类

    支持缩略图和水印. using System; using System.IO; using System.Linq; using System.Web; using System.Web.Helpe ...

  8. 基于AFNetworking封装的网络请求工具类【原创】

    今天给大家共享一个我自己封装的网络请求类,希望能帮助到大家. 前提,导入AFNetworking框架, 关于修改AFN源码:通常序列化时做对text/plan等的支持时,可以一劳永逸的修改源代码,在a ...

  9. 分享非常好用的前端分页js工具类 灵活 简单易懂

    分享自己封装的前端分页js工具类  下面是默认样式效果截图 可以随意更改js及css 很灵活 /** * pageSize, 每页显示数 * pageIndex, 当前页数 * pageCount 总 ...

随机推荐

  1. C++初步 2

    对象数组: Coordinate coord[3];  栈区           Coordinate *p=new Coordinate[3];    堆区 /* * Coordinate.h * ...

  2. vue的风格指南(必要的)

    1.v-if与v-for不要放在同一个元素上 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级.永远不要把 v-if 和 v-for 同时用在同一个元素上. 一般我 ...

  3. 连接Redis_五种数据格式

    前面我们已经准备成功开启Redis服务,其端口号为6379,接下来我们就看看如何使用C#语言来操作Redis.就如MongoDB一样,要操作Redis服务,自然就需要下载C#的客户端,这里通过Nuge ...

  4. Linux 结构化命令

    if -then 语句 if -then 语句有如下格式 if command then commands f i bash shell 的if语句会先运行if后面的那个命令,如果改命令的退出状态码是 ...

  5. VIM常用快捷键(转载)

    移动光标 h,j,k,l 上,下,左,右 ctrl-e 移动页面 ctrl-f 上翻一页 ctrl-b 下翻一页 ctrl-u 上翻半页 ctrl-d 下翻半页 w 跳到下一个字首,按标点或单词分割 ...

  6. 从url中获得域名

    import java.net.MalformedURLException; import java.net.URL; /** * * @author csh * */ public class AA ...

  7. layui select使用问题

    1.需要引用form模板 layui.use(['form'], function () { var form = layui.form; }); 2.html代码 <div class=&qu ...

  8. swust oj 987

    输出用先序遍历创建的二叉树是否为完全二叉树的判定结果 1000(ms) 10000(kb) 2553 / 5268 利用先序递归遍历算法创建二叉树并判断该二叉树是否为完全二叉树.完全二叉树只能是同深度 ...

  9. 微信小程序发送短信验证码完整实例

    微信小程序注册完整实例,发送短信验证码,带60秒倒计时功能,无需服务器端.效果图: 代码: index.wxml <!--index.wxml--> <view class=&quo ...

  10. JAVA基础—适配器设计模式

    适配器概念 在计算机编程中,适配器模式将一个类的接口适配成用户所期待的.使用适配器,可以使接口不兼容而无法在一起工作的类协调工作,做法是将类自己包裹在一个已经存在的类中. JDK对适配器设计模式的应用 ...