声明:本文为作者原创文章,转载请注明出处 https://www.cnblogs.com/MaMaNongNong/p/8904022.html

问题背景:

  最近做一个非常简单的功能,就是使用ajax请求的方式从服务端请求一段下拉表的数据。

  以前也有做过这个功能,只不过这次做这个功能的时候冒出了一个想法:

  我请求的这段数据它是一段相对比较固定的数据,也就是说它不怎么改变,也许几个月才会改变一次。由于这种数据的变化周期很长,所以以前做这种功能的时候,会使用缓存进行优化,可以直接从缓存中读取数据,避免每一次接收了ajax请求后都要向数据库要数据,减少服务器与数据库之间的交互,减轻数据库服务器的压力。但是问题来了,数据的变化周期再长终究是要变化的,当数据库中的数据变化的时候你就要对旧有的缓存内容进行移除(remove)操作,好的,以前我是这样做的:

        public ActionResult GetAllFJs()
{
//尝试从缓存中取出数据
var FJIdNames = HttpContext.Cache["FJIdNames"]; if (null == FJIdNames) //缓存中没有数据
{
//从数据库中查询出数据
FJIdNames = FJService.GetAll().Select(fj => new { Id = fj.Id, Name = fj.Name }).ToArray(); //将数据缓存起来下一次用(设置一个缓存有效时间,使用绝对过期,到达指定过期时间,缓存失效) HttpContext.Cache.Insert(
"FJIdNames", //缓存项的键(string)
FJIdNames, //缓存项的值(object)
null,
DateTime.UtcNow.AddMinutes(30), //绝对到期时间(DateTime)
System.Web.Caching.Cache.NoSlidingExpiration //滑动到期间隔时间(TimeSpan)
);
} //将得到的数据转化成json格式字符串
string jsonResult = CommonHelper.ConvertToJsonStr(FJIdNames); //返回给浏览器的结果字符串
return Content(jsonResult);
}

说明:这是一个 asp.net MVC 中处理一个请求的action方法,其中有一个重要的方法

public void Insert(

  string key,                                             --> 缓存项的键

  object value,                --> 缓存项的值

  CacheDependency dependencies,           --> 缓存依赖项(这里不用,后面会用,是重头戏)

  DateTime absoluteExpiration,               --> 绝对过期时间点

  TimeSpan slidingExpiration                   --> 滑动过期时间间隔

);

  在这里是利用了缓存的过期时间来对缓存数据进行更新操作,每当缓存数据经过了30分钟后就要重新从数据库中拿一次数据来更新缓存中的内容,来看一下执行的结果   (为了便于展示结果,将绝对过期时间调为30s):

第一次请求

(数据库表中此刻的数据):

(执行结果):

第一次请求的话肯定缓存中是没有数据的,所以要向数据库要数据;

第二次请求

(请求之前改变一下数据库中相应表的数据)

(执行结果):

第二次请求,由于没有到缓存项的绝对过期时间,缓存中还有数据,不用向数据库要数据,从缓存中取出来就行;

过30s后再请求

(数据库表中此刻的数据):

(执行结果):

缓存中数据已经过期被移除,需要重新向数据库请求;

  从以上三次请求可以看到,最后的确是实现了缓存数据的更新。

  但同样可以看到这样做有一个坏处:在还没到达过期时间的这段时间里,请求的数据依然是原来的缓存中数据,和数据库中的数据并不一致。

  其中设置的绝对过期时间点要根据实际的数据刷新的可容忍度来进行设定,而恰好在我的这个应用场景中的可容忍度最不能把握,它要求的是 当数据库中的数据改变以后,缓存中对应的数据在下一次请求结束后一定要马上跟着改变,当然你也可以把过期时间尽可能的调小,调到一秒。当然,这样的话还是要频繁的向数据库进行请求,那不是背离了我们原本使用缓存优化的目的了吗?

  所以现在的问题是:有没有一种方法能让数据库和服务器程序建立一种联系,这种联系好比是一种“心灵感应”,当数据库表中的数据发生变化的时候,马上就能让服务器中的对应的缓存项“感应”到这个变化,从而让原来的缓存项失效呢?答案当然是,有的。

数据库依赖缓存,对,是它,就是它。

  ASP.NET 有 3 种类型的依赖:

  • 缓存项目依赖
  • 文件或文件夹依赖
  • 数据库依赖

  本文要讲的是数据库依赖:数据库缓存依赖是一项当数据库中的相关数据被修改时自动使缓存的数据对象失效的技术。

  以前不知道有 数据库依赖 的时候,有想过使用文件或文件夹依赖来实现类似于数据库依赖缓存的功能,大概的思路就是:用某个文件作为媒介,在进行了对数据库表的数据改动后,同时改动一下该文件来触发缓存的失效。还好我在看了大神们写的博文以后,马上停止了我“愚蠢”的想法,那样做其实是画蛇添足,而且并不能很好的实现,有现成的数据库依赖不用干嘛。

 

 我们来看一下如何使用它:

 1、配置:

  1)在当前网站mvc项目下的Web.config文件中加入

<!--(数据库连接字符串)<configuration> 结点下配置-->

<connectionStrings>
<add name="connStr" connectionString="server=127.0.0.1; user id=sa; password=root; database=LZXF" providerName="System.Data.SqlClient" />
</connectionStrings>
 <!--(缓存数据库依赖配置)<system.web> 结点下配置-->
<caching>
<sqlCacheDependency enabled="true">
<databases>
<add name="LZXF" pollTime="5000" connectionStringName="connStr" />
</databases>
</sqlCacheDependency>
</caching>

  

  2)在 Application_Start() 中加入

            //配缓存数据库依赖
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["connStr"].ToString();
//启动数据库的数据缓存依赖功能
SqlCacheDependencyAdmin.EnableNotifications(connectionString);
//启用数据表缓存
SqlCacheDependencyAdmin.EnableTableForNotifications(connectionString, "(表名)"); //第二个参数可以是单个表名或表名的数组

 2、代码部分

        public ActionResult GetAllFJs()
{
//尝试从缓存中取出数据
var FJIdNames = HttpContext.Cache["FJIdNames"]; if (null == FJIdNames) //缓存中没有数据
{
//从数据库中查询出数据
FJIdNames = FJService.GetAll().Select(fj => new { Id = fj.Id, Name = fj.Name }).ToArray(); //将数据缓存起来下一次用(使用数据库依赖的缓存,当数据库中对应的表的数据发生改变时,缓存失效)
HttpContext.Cache.Insert("FJIdNames", FJIdNames, new SqlCacheDependency("LZXF", "T_FJs"));
} //将得到的数据转化成json格式字符串
string jsonResult = CommonHelper.ConvertToJsonStr(FJIdNames); //返回给浏览器的结果字符串
return Content(jsonResult);
}

  其中的 SqlCacheDependency(数据库缓存依赖类) 是最重要的一个类,就是它建立起了数据库和服务器程序之间 “沟通的桥梁” ,

  使用它的一个构造方法:

  public SqlCacheDependency(string databaseEntryName, string tableName) 来创建一个数据库缓存依赖类对象,传给创建缓存项的方法Insert, 这样来建立该缓存项的数据库依赖,每当该指定表中发生数据的变动时都会销毁该缓存项。

看一下执行结果:

没改变数据库表数据之前:

(执行结果):

改变数据库表数据之后:

(执行结果):

改变了数据库表的数据以后再去请求数据,请求到最新的数据,说明旧的缓存被移除了

既然都会用了,那接下来要看的就是原理,(原理,原理最重要)

用完了以后就会很疑惑,它是怎么实现的呢?

思考:首先是改动了数据库表中的数据,这一步操作以后必定要引发某种操作。在数据库中改变表中数据会触发操作?讲的不就是触发器吗。

来看一下数据库中多了些什么:

打开sqlServerManagement查看数据库发现

多了一个 AspNet_SqlCacheTablesForChangeNotification 表,表中内容:

要找的触发器在这里:

看一下触发器里面的内容:

说的就是:当 T_FJs 表中发生了 INSERT, UPDATE, DELETE 这些操作,就去执行 dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure 这个存储过程,这个存储过程是我们开启sql server的缓存依赖自动生成的

找一下存储过程 dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure,在这里:

内容是:

所以最后对原理的总结,我就引用一篇大神博客(https://www.lanhusoft.com/Article/290.html)里的总结:

  当sql server启用缓存依赖之后,就会在对应的数据库添加相应的表、触发器和一些存储过程。它是利用触发器来监测表的数据的变化,如果有增、删、改就插入数据到通知表,然后通知订阅这个通知的网站此缓存项失效。

最后要说的是使用缓存依赖也有限制:必须用ASP.Net和SQL Server开发应用,也就是SqlCacheDependency是基于微软的那套体制。

参考博文地址:

  https://www.cnblogs.com/SkySoot/archive/2012/08/15/2640559.html

  https://www.lanhusoft.com/Article/290.html

 这是我的第一篇博文,以前想过为什么要写博文这个问题?现在网上随便一搜都有自己想要的内容,而且有些大神写的很不错。后来慢慢的发现每一次遇到问题都要上网搜博客看,而且很多时候遇到的是同一个问题,可能以前就已经思考过了,现在又要浪费时间去从头找着看已经看过的东西,那我为什么不自己写好了整理好了存着呢。当然,方便自己的同时,希望也能方便到正在阅读本文的你。谢谢!

Asp.net 数据库依赖那些事的更多相关文章

  1. ASP.NET MVC 数据库依赖缓存的实现

    当数据库中的信息发生变化的时候,应用程序能够获取变化的通知是缓存依赖得以实现的基础.应用程序可以通过轮询获取数据变化的信息,使用轮询的话也不可能重新查一次后再和以前的数据做比较,如果这样的话如果我一个 ...

  2. Asp.net数据库缓存依赖

    Asp.net数据库缓存依赖 更多的时候,我们的服务器性能损耗还是在查询数据库的时候,所以对数据库的缓存还是显得特别重要,上面几种方式都可以实现部分数据缓存功能.但问题是我们的数据有时候是在变化的,这 ...

  3. 初遇 Asp.net MVC 数据库依赖缓存那些事儿

    问题背景: 最近做一个非常简单的功能,就是使用ajax请求的方式从服务端请求一段下拉表的数据. 以前也有做过这个功能,只不过这次做这个功能的时候冒出了一个想法: 我请求的这段数据它是一段相对比较固定的 ...

  4. ASP.NET MVC 数据库依赖缓存

    ASP.NET MVC 数据库依赖缓存   问题背景 最近做一个非常简单的功能,就是使用ajax请求的方式从服务端请求一段下拉表的数据. 以前也有做过这个功能,只不过这次做这个功能的时候冒出了一个想法 ...

  5. 实现BUG自动检测 - ASP.NET Core依赖注入

    我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...

  6. 自动化CodeReview - ASP.NET Core依赖注入

    自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 我个人比较懒,能自动做的事绝 ...

  7. 转:你需要知道的NoSQL数据库10件事

    你需要知道的NoSQL数据库10件事 NoSQL的5个优势 1.弹性扩展 多年来,数据库管理员一直依赖于向上扩展(scale up)-随着数据库负载的增加购买更大的数据库服务器―而不是向外扩展-随着负 ...

  8. [译]ASP.NET Core依赖注入深入讨论

    原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...

  9. asp.net core 依赖注入几种常见情况

    先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...

随机推荐

  1. sed 很棒的介绍

    选项与参数:-n :使用安静(silent)模式.在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上.但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作) ...

  2. [Atcoder Grand Contest 002] Tutorial

    Link: AGC002 传送门 A: …… #include <bits/stdc++.h> using namespace std; int a,b; int main() { sca ...

  3. [BZOJ 3170] 松鼠聚会

    Link: BZOJ 3170 传送门 Solution: $Knowledge Point:$ 切比雪夫距离$DIST(a,b)=max\{ |X'_a-X'_b|,|Y'_a-Y'_b|\}$ 曼 ...

  4. [Baltic2003] Gem

    [Baltic2003]Gem Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 501  Solved: 320[Submit][Status][Discu ...

  5. [UOJ198]时空旅行

    看懂题目就知道$y,z$是没用的,这题相当于是给一堆$(x_i,c_i)$和询问$x_q$,要求$(x_q-x_i)^2+c_i$的最大值 先把这个式子拆开:$-2x_ix_q+x_i^2+c_i+x ...

  6. 【数学期望】【高斯消元】bzoj3143 [Hnoi2013]游走

    和hdu5955很像.也是注意从结点1出发,其概率要在方程左侧+1. 边的期望和点的期望之间转换巧妙 http://blog.csdn.net/thy_asdf/article/details/473 ...

  7. Error: Top-level design entity "demo" is undefined

    原因:顶层模块的module名没有和工程名同名 解决方法:把顶层模块 module名改成和工程名同名 最近在玩QUARTUS 11遇到此问题! 问题补充:本人用的时VERILOG HDL硬件描述语言! ...

  8. Ado.Net基础拾遗一:读取数据

    从数据库中读取数据: 使用DataReader对象从数据库中读取数据 首先需要添加几个命名空间 //需要添加的命名空间 using System.Configuration; using System ...

  9. [shell编程] sh脚本异常:/bin/sh^M:bad interpreter: No such file or directory

    转载地址:http://www.cnblogs.com/pipelone/archive/2009/04/17/1437879.html 在Linux中执行.sh脚本,异常/bin/sh^M: bad ...

  10. win8 下脚本安装IIS

    @echo off      echo 正在添加IIS8.0 功能,依据不同的网络速率,全程大约需要5分钟时间...      start /w pkgmgr /iu:IIS-WebServerRol ...