• ASP.NET缓存 Cache


    缓存介绍

    如果每次进入页面的时候都查询数据库生成页面内容的话,如果访问量非常大,则网站性能会非常差,
    而如果只有第一次访问的时候才查询数据库生成页面内容,以后都直接输出内容,则能提高系统性能,
    这样无论多少人访问都只访问一次数据库,数据库压力不变
    缓存是一种用空间换取时间的技术,存在于计算机中很多地方,用来将一些慢速设备中的常用数据保存
    在快速设备中,取数据的时候直接从快速设备中取,比如CPU二级缓存,WINDOWS文件读取缓存
    缓存存在失效的问题:为了保证从缓存中读取数据和慢速数据中数据一致,则需要在慢速数据中对应
    的数据发生变化的时候,清除缓存中相应的数据
    缓存是改进网站性能的第一个手段,就像索引是改进数据库性能的第一个手段一样


    ASP.NET缓存主要分为:

    页面缓存,

    数据源缓存,

    数据缓存

    1.页面缓存
    给页面添加 <%@OutputCache Duration="15" VaryByParam="none"%> 标签就可以启用页面缓存,
    这样整个页面的内容都会被缓存,页面中的ASP.NET代码,数据源在缓存期间都不会运行,而是直接
    输出缓存的页面内容,Duration 表示缓存时候,以秒为单位,超过这个时间则缓存失效,再次生成以
    后会再缓存15秒,以些类推,在在Page_Load处设置断点,修改数据库可测试
    缓存是存在服务器,不是客户端,因为用HttpWatch还是能看到向服务器提交请求

    缓存是针对所有这个页面的访问者,这样1个访问者和 1万个访问者,一次访问和100万次访问对数据
    的压力是一样的
    对于看新闻页面来讲,如果如上设置的话,则会缓存在第一个看到的新闻,因为?id=2,?id=3只是页面
    的不两只参数而已,为了能让不同的新闻各自缓存,因此可以设置VaryByParam="id",表示对于不同的
    id参数进行单独缓存,如果有多个确定缓存的参数,则将参数名用 分号; 隔开即可,比如VaryByParam="id;num"
    如果想让任何不同的查询字符串都创建不同的缓存,则设置VaryByParam="*",一般情况下设置*就足够
    在WebUserControl中也可以像页面缓存一样设置控件的缓存

    2.数据源缓存

    设定ObjectDataSource的CacheDuration (缓存时间:秒),EnableCaching=true
    这样每隔CacheDuration指定的时间段才调用SelectMethod指定的方法来执行数据库查询,
    其他时候都是直接返回缓存的数据。
    缓存固定的时间适用于首页、文章列表等访问频繁的页面,对于看贴页面则不适合,假设有100万个
    帖子,如果每个帖子都是固定缓存1小时的话,假设一小时之内有10万个帖子被看了,那么就要缓存
    十万个帖子,非常占用内存,因为“百年一看”的“坟帖”偶然被访问一次也缓存一个小时,占用内存
    这时候可以采用“滑动窗口(sliding)”策略,比如帖子缓存10分钟,如果10分钟之内又访问了,则
    缓存的失效时间修改为从被访问这一刻起的10分钟之后,以此类推。这样经常访问的帖子就可以“长
    期缓存”,而不经常访问的帖子也不会因为偶然访问而长期占用缓存。设置方法,
    数据源:CacheExpirationPolicy="Sliding"
    貌似滑动有问题。不是问题,Sliding只是策略,服务器会参考

    3.缓存其他 (自定义缓存)

    页面缓存、数据源缓存等内部都是使用HttpRuntime.Cache来实现缓存的,在一些页面缓存、数据源
    缓存完成不了的特殊的缓存要求中,可以直接调用HttpRuntime.Cache进行缓存。在如鹏网项目中会讲到
    (*)ASP.Net缓存默认是保存在内存中的,还可以配置保存到数据库中,大型网站还会配合使用Memcached等技术
    清除缓存。在缓存还未失效的时候可能需要立即清空缓存,让数据库的修改立即反映到界面中
    ASP.Net没有提供现成的方法,可以使用Hack级别的代码

    // 保存缓存  null 表示缓存依赖
    // 键,值,缓存依赖对象,绝对过期时间,区间
    Cache.Insert("user","xgao",null,DateTime.Now.AddSeconds(10),TimeSpan.Zero);
    
    // 简单保存缓存
    Cache["test"] = "这是一个测试!";
    
    //读取缓存
    lbl.text = Cache["user"];
    缓存依赖(依赖于文件)

    原理:它是依赖指定的文件,一但文件被删除,修改,缓存将也会被删除

    依赖于文件内容 CacheDependency cDep = new CacheDependency(filePath);

    实例如下: 实现当文件内容不变的时候,就读缓存的,内容一变就更新缓存

    protected void Page_Load(object sender, EventArgs e)
    {
        
        if (Cache["fileText"] == null)
        {
        Response.Write("文件被修改,缓存被删除,但又创建了新的缓存,下次访问可得到!");
        // 得到指定文件的物理路径
        string filePath = Server.MapPath("~/CacheDep.txt");
        // 读取指定文件
        string Text = File.ReadAllText(filePath);
    
        // 创建缓存的文件依赖对象(依赖的文件的服务物理路径)
        CacheDependency cDep = new CacheDependency(filePath);
        // 键,值,缓存依赖对象,无绝对过期时间,无滑动过期时间,优先级,更新回调函数
        Cache.Insert("fileText", Text, cDep,
            System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, 
            System.Web.Caching.CacheItemPriority.Normal, callback);
        }
        else
        {
        Response.Write(Cache["fileText"].ToString());
        }
    }
    
    // 缓存依赖的回调函数(当缓存被清除时调用些方法)
    public void callback(string key, object value, CacheItemRemovedReason reason)
    {
        string filePath = Server.MapPath("~/CacheLog.txt");
        string msg = "Cache["+key+"]="+value+"缓存被移除,因为:"+reason+"
    ";
        File.AppendAllText(filePath, msg);
    }
    缓存依赖(依赖于数据库)

    依赖于数据库内容(轮询机制/通知机制)

    轮询机制: 是FW不定期的去检查数据库

    1.在数据库新建版本表(ID、Ver 字段 用来保存某张表的版本)
    2.在数据库新建触发器(比如在新闻表上新建)
    3.使用C:WINDOWSMicrosoft.NETFrameworkv2.0.50727中的aspnet_regsql.exe:
    注册:aspnet_regsql -S . -E -ed -d 数据库名 -et -t 版本表名
    删除:aspnet_regsql -S . -E -d 数据库名 -dt -t 版本表名
    取消数据库缓存依赖: aspnet_regsql -S . -E -dd 数据库名 版本表名
    列出已注册表:aspnet_regsql -S . -E -d 数据库名 –lt
    4.配置web.config
    5.数据库依赖对象
    SqlCacheDependency cDep = new SqlCacheDependency("DepName", "BankVer");

    aspnet_regsql -S(服务器) . -E(集成登陆)/-U sa -P 123 -ed(启动/-dd关闭) -d(数据库名) GSSMS -et(指定缓存依赖的表名/-dt禁用表名) -t(表名) Aticle


    数据库依赖 实例:

    1>. 表bank如下:
    ------------------------
    ID Name Maney
    ------------------------
    1 xgao 1000
    2 zsan 1
    3 lshi 2000
    ------------------------

    表BankVer如下:
    --------------
    ID VerNum
    --------------
    1 0
    --------------

    2>. 在bank表里创建触发器:

    create Trigger [bankTri]
    on [bank]
    for insert,update,delete
    as
      update BankVer set VerNum=VerNum+1

    3>. 开启数据库的缓存依赖(CMD下运行):

    aspnet_regsql -S . -E -ed -d TestData -et -t BankVer

    4>. 在网站的 web.config配置在 <system.web> 下:

    <caching>
      <sqlCacheDependency enabled="true">
        <databases>
            <!-- pollTime为轮询时间间隔 15 秒  -->
        <add name="DepName" connectionStringName="conStr" pollTime="15000"/>
        </databases>
      </sqlCacheDependency>
    </caching>

    5>. 前台代码:

     <form id="form1" runat="server">
        <div>
            <asp:GridView ID="gvBankList" runat="server"></asp:GridView>
        </div>
      </form>

    6>. 后台代码:

     protected void Page_Load(object sender, EventArgs e)
            {
                if (Cache["bankList"] == null)
                {
                    Response.Write("数据以更改!以下从数据库读取的!</br>");
    
                    DataTable dt = GetBankList();
                    gvBankList.DataSource = dt;
                    gvBankList.DataBind();
    
                    SqlCacheDependency sqlDep = new SqlCacheDependency("DepName", "BankVer");
                    Cache.Insert("bankList", dt, sqlDep, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Normal,callback);
    
                }
                else
                {
                    Response.Write("以下是从缓存里读取的</br>");
                    gvBankList.DataSource = Cache["bankList"];
                    gvBankList.DataBind();
                }
            }
            public void callback(string key,object value,CacheItemRemovedReason reason)
            {
                string filePath = Server.MapPath("~/CacheLog.txt");
                string msg = "数据库依赖 Cache[" + key + "]=" + value + "缓存被移除,因为:" + reason + "
    ";
                File.AppendAllText(filePath, msg);
            }
    
            public DataTable GetBankList()
            {
                string connStr = ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
                SqlConnection conn = new SqlConnection(connStr);
                SqlCommand cmd = conn.CreateCommand();
                cmd.CommandText = "select * from bank";
    
                DataSet ds = new DataSet();
                SqlDataAdapter sda = new SqlDataAdapter(cmd);
                sda.Fill(ds);
                return ds.Tables[0];
            }

    所使用的通知机制:是数据通信FW

  • 相关阅读:
    阿里P8聊并发编程:线程中断和终止
    浅谈Java中的锁:Synchronized、重入锁、读写锁
    史上最全Java面试题!进程,线程相关部分下篇(带全部答案)
    @史上最全Java面试题!关于volatile关键字篇(带全部答案)
    @史上最全Java面试题!进程,线程相关部分上篇(带全部答案)
    一道号称“史上最难”java面试题引发的线程安全思考,掌握了吗?
    stopWatch
    mysql语句及执行计划
    Awr
    文件下载
  • 原文地址:https://www.cnblogs.com/xgao/p/4174232.html
Copyright © 2020-2023  润新知