文档章节

SQL server数据缓存依赖

随智阔
 随智阔
发布于 2015/12/21 18:50
字数 2693
阅读 40
收藏 0

SQL server数据缓存依赖有两种实现模式,轮询模式,通知模式。

1  轮询模式实现步骤

此模式需要SQL SERVER 7.0/2000/2005版本以上版本都支持

       主要包含以下几步:

1.1 使用aspnet_regsql命令行或SqlCacheDependencyAdmin来配置连接数据库

ALTER DATABASE <DatabaseName> SET ENABLE_BROKER;  //启用 ServiceBroker,需要在数据库中执行,或者在数据库右键属性,选项中修改ENABLE BROKER为true

           //注意修改时,需要关闭所有和此数据库关联的窗口,否则修改不成功。

            报如下错误:

                         Alter failed for Database 'pu'.  (Microsoft.SqlServer.Smo)         
                         An exception occurred while executing a Transact-SQL statement or batch. (Microsoft.SqlServer.ConnectionInfo)             
                       Database state cannot be changed while other users are using the database 'pu'
                      ALTER DATABASE statement failed. (Microsoft SQL Server, Error: 5070)

                aspnet_regsql -S <server> -U sa -P sa -d <database> -ed     启动数据库的数据缓存依赖功能

               aspnet_regsql -S <server> -U sa -P sa -d <database> -t <table> -et     启动数据表的数据缓存依赖功能

            注意:系统默认不能识别aspnet_regsql,.net 4.0中aspnet_regsql的默认路径为C:\Windows\Microsoft.NET\Framework\v4.0.30319,需要首先把当前目录修改为C:\Windows\Microsoft.NET\Framework\v4.0.30319,才可以执行此命令。

1.2  配置文件

[html] view plaincopy

  1. <?xmlversion="1.0"?>
  2. <configuration>
  3. <connectionStrings>
  4. <add name="PubsConnectionString"connectionString="Data Source=10.32.153.165; Initial Catalog=pubs;uid=sa;pwd=q1w2e31@;"providerName="System.Data.SqlClient"/>
  5. </connectionStrings>
  6. <system.web>
  7. <compilationdebug="true"targetFramework="4.0"/>
  8. <caching>
  9. <sqlCacheDependencyenabled ="true"pollTime ="1000">
  10. <databases>
  11.           <!--name:必需的 String 属性。 要添加到配置集合中的 SqlCacheDependencyDatabase 对象的名称。
  12.               此名称用作 @ OutputCache 指令上 SqlDependency 属性的一部分。
  13.           pollTime:设置 SqlCacheDependency 轮询数据库表以查看是否发生更改的频率(以毫秒计算)。这儿是一个测试,所以设为10秒,请加大此值
  14.           connectionStringName 必选的 String 特性。为数据库设置连接字符串名称。 在 connectionStrings 元素(ASP.NET 设置架构) 配置节中引用连接字符串。-->
  15. <addname="Pubs"connectionStringName = "PubsConnectionString"/>
  16. </databases>
  17. </sqlCacheDependency>
  18. </caching>
  19. </system.web>
  20. </configuration>

[html] view plaincopy

  1. <?xml version="1.0"?>
  2. <configuration>
  3. <connectionStrings>
  4. <add name="PubsConnectionString" connectionString="Data Source=10.32.153.165; Initial Catalog=pubs;uid=sa;pwd=q1w2e31@;" providerName="System.Data.SqlClient" />
  5. </connectionStrings>
  6. <system.web>
  7. <compilation debug="true" targetFramework="4.0" />
  8. <caching>
  9. <sqlCacheDependency enabled = "true" pollTime = "1000" >
  10. <databases>
  11.           <!--name:必需的 String 属性。 要添加到配置集合中的 SqlCacheDependencyDatabase 对象的名称。 
  12.               此名称用作 @ OutputCache 指令上 SqlDependency 属性的一部分。 
  13.           pollTime:设置 SqlCacheDependency 轮询数据库表以查看是否发生更改的频率(以毫秒计算)。这儿是一个测试,所以设为10秒,请加大此值 
  14.           connectionStringName 必选的 String 特性。为数据库设置连接字符串名称。 在 connectionStrings 元素(ASP.NET 设置架构) 配置节中引用连接字符串。-->
  15. <add name="Pubs" connectionStringName = "PubsConnectionString" />
  16. </databases>
  17. </sqlCacheDependency>
  18. </caching>
  19. </system.web>
  20. </configuration>

注意:connectionStrings,和caching两节的关系,caching节的connectionStringName需要和connectionStrings中的name对应的。

1.3   SqlCacheDependencyAdmin使用

[csharp] view plaincopy

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.UI;
  6. using System.Web.UI.WebControls;
  7. using System.Web.Caching;
  8. using System.Configuration;
  9. using System.Data.SqlClient;
  10. namespace TestWebSqlCacheDependency
  11. {
  12. public partial class _Default : System.Web.UI.Page
  13.     {
  14. string key = "model_type";
  15. protected void Page_Load(object sender, EventArgs e)
  16.         {         
  17.             TextBox1.Text = test();// test();
  18.         } 
  19. private string test()
  20.         {
  21. //从缓存中取值
  22. string model = null;
  23. if (HttpRuntime.Cache[key] !=null)
  24.             {
  25.                 model = HttpRuntime.Cache[key].ToString();
  26.             }
  27. if (model ==null)
  28.             {
  29. //取数据
  30.                 model = getDBValue();
  31. //启用更改通知
  32.                 SqlCacheDependencyAdmin.EnableNotifications(
  33.     ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString);
  34. //连接到 SQL Server 数据库并为 SqlCacheDependency 更改通知准备数据库表
  35.                 SqlCacheDependencyAdmin.EnableTableForNotifications(
  36.     ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString,"TableTest");//第二个参数是要监控的表名称
  37. //制定缓存策略
  38.                 SqlCacheDependency scd = new SqlCacheDependency("Pubs","TableTest");
  39. //注意此处的Pubs需要要配置文件的caching节下的databases节下的name对应,而不是随便写的,目前个人测试的结论就是这样。第二个参数是要监控的表名称
  40. //插入缓存
  41.                 HttpRuntime.Cache.Insert(key, model, scd);
  42.             }
  43. return model;
  44.         }
  45. private string getDBValue()
  46.         {
  47.             SqlConnection cn = newSqlConnection(ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString);
  48.             cn.Open();
  49.             SqlCommand cd = cn.CreateCommand();
  50.             cd.CommandText = " select top 1 TableTest.col2 from TableTest ";
  51. object o = cd.ExecuteScalar();
  52.             cn.Close();
  53. if (o != null)
  54.             {
  55. return o.ToString();
  56.             }
  57. return null;
  58.         }
  59.     }
  60. }

[csharp] view plaincopy

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Web; 
  5. using System.Web.UI; 
  6. using System.Web.UI.WebControls; 
  7. using System.Web.Caching; 
  8. using System.Configuration; 
  9. using System.Data.SqlClient; 
  10. namespace TestWebSqlCacheDependency 
  11. public partial class _Default : System.Web.UI.Page 
  12.     { 
  13. string key = "model_type"; 
  14. protected void Page_Load(object sender, EventArgs e) 
  15.         {          
  16.             TextBox1.Text = test();// test();
  17.         }  
  18. private string test() 
  19.         { 
  20. //从缓存中取值
  21. string model = null; 
  22. if (HttpRuntime.Cache[key] != null) 
  23.             { 
  24.                 model = HttpRuntime.Cache[key].ToString(); 
  25.             } 
  26. if (model == null) 
  27.             { 
  28. //取数据
  29.                 model = getDBValue(); 
  30. //启用更改通知
  31.                 SqlCacheDependencyAdmin.EnableNotifications( 
  32.     ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString); 
  33. //连接到 SQL Server 数据库并为 SqlCacheDependency 更改通知准备数据库表
  34.                 SqlCacheDependencyAdmin.EnableTableForNotifications( 
  35.     ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString, "TableTest");//第二个参数是要监控的表名称
  36. //制定缓存策略
  37.                 SqlCacheDependency scd = new SqlCacheDependency("Pubs", "TableTest"); 
  38. //注意此处的Pubs需要要配置文件的caching节下的databases节下的name对应,而不是随便写的,目前个人测试的结论就是这样。第二个参数是要监控的表名称
  39. //插入缓存
  40.                 HttpRuntime.Cache.Insert(key, model, scd); 
  41.             } 
  42. return model; 
  43.         } 
  44. private string getDBValue() 
  45.         { 
  46.             SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString); 
  47.             cn.Open(); 
  48.             SqlCommand cd = cn.CreateCommand(); 
  49.             cd.CommandText = " select top 1 TableTest.col2 from TableTest "; 
  50. object o = cd.ExecuteScalar(); 
  51.             cn.Close(); 
  52. if (o != null) 
  53.             { 
  54. return o.ToString(); 
  55.             } 
  56. return null; 
  57.         } 
  58.     } 

      轮询模式的实质,就是在数据库中多了一个表AspNet_SqlCacheTablesForChangeNotification,在需要监视改变的表也多了一个Trigger,触发器名称为:表名_AspNet_SqlCacheNotification_Trigger,在每次表中有数据时,会触发此触发器,向AspNet_SqlCacheTablesForChangeNotification表中插入数据,系统会隔一段时间查询一次,发现有改变时,就会清空相对应的cache,caching节的pollTime其实就是查询间隔,也就是说,如果此时间设置的很长,数据库中的数据修改后,需要很长时间,才能清空对应的cache,最长延时可到达pollTime对应的时间,性能并不是很好。

  2  通知模式实现步骤

SQL SERVER 2005(包括SQL SERVER 2005)以上的数据库才可以使用。

    2.1 启用Service Broker

             Select DATABASEpRoPERTYEX('数据库名称','IsBrokerEnabled') --检测是否启用了 ServiceBroker,1 表示已经启用 0 表示没有启用

          ALTER DATABASE <DatabaseName> SET ENABLE_BROKER;  //启用 ServiceBroker,需要在数据库中执行,或者在数据库右键属性,选项中修改 ENABLE BROKER为true, 与轮询模式完全一致,但不要aspnet_regsql相应的脚本。

2.2  启动调用SqlDependency.Start,结束时调用SqlDependency.Stop()

       最好放进Global中,例如:

[csharp] view plaincopy

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.Security;
  6. using System.Web.SessionState;
  7. using System.Data.SqlClient;
  8. using System.Web.Caching;
  9. namespace WebTest2
  10. {
  11. public class Global : System.Web.HttpApplication
  12.     {
  13. void Application_Start(object sender, EventArgs e)
  14.         {
  15.             #region SQL2005
  16.             SqlDependency.Start(ConnectionString_SQL2005);//推荐将这段代码加到Global.asax的Application_Start方法中
  17.             #endregion
  18.         }
  19. void Application_End(object sender, EventArgs e)
  20.         {
  21.             SqlDependency.Stop(ConnectionString_SQL2005);
  22.         }     
  23.     }
  24. }

[csharp] view plaincopy

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Web; 
  5. using System.Web.Security; 
  6. using System.Web.SessionState; 
  7. using System.Data.SqlClient; 
  8. using System.Web.Caching; 
  9. namespace WebTest2 
  10. public class Global : System.Web.HttpApplication 
  11.     { 
  12. void Application_Start(object sender, EventArgs e) 
  13.         { 
  14.             #region SQL2005
  15.             SqlDependency.Start(ConnectionString_SQL2005);//推荐将这段代码加到Global.asax的Application_Start方法中
  16.             #endregion
  17.         } 
  18. void Application_End(object sender, EventArgs e) 
  19.         { 
  20.             SqlDependency.Stop(ConnectionString_SQL2005); 
  21.         }      
  22.     } 

     调试时注意一定要运行SqlDependency.Start()这句,否则就会出错,所以测试时不要使用预览模式。由于vs会启动WebDev.WebServer40.EXE ,导致SqlDependency.Start()可能就没有运行,所以调试时一定要把VS启动的WebDev.WebServer40.EXE的前一次模拟服务停止了,使vs重新启动WebDev.WebServer40.EXE,并运行SqlDependency.Start()。

   2.3  使用

[csharp] view plaincopy

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.UI;
  6. using System.Web.UI.WebControls;
  7. using System;
  8. using System.Configuration;
  9. using System.Collections.Generic;
  10. using System.Data;
  11. using System.Data.SqlClient;
  12. using System.Web;
  13. using System.Web.UI;
  14. using System.Web.UI.WebControls;
  15. using System.Web.Caching;
  16. namespace WebTest2
  17. {
  18. public partial class _Default : System.Web.UI.Page
  19.     {
  20. protected void Page_Load(object sender, EventArgs e)
  21.         {          
  22.             DataTable dt = HttpRuntime.Cache["dt"]as DataTable;
  23. if (dt == null)
  24.             {
  25. using (SqlConnection sqlCon =newSqlConnection(WebConfigHelper.ConnectionString_SQL2005))
  26.                 {
  27.                     sqlCon.Open();
  28.                     SqlCommand sqlCmd = new SqlCommand();
  29.                     sqlCmd.Connection = sqlCon;
  30.                     sqlCmd.CommandText = "select col2 from dbo.TableTest";
  31.                     dt = new DataTable();
  32.                 SqlCacheDependency scd = new SqlCacheDependency(sqlCmd);    
  33.                     SqlDataAdapter sda = new SqlDataAdapter(sqlCmd);                   
  34.                     sda.Fill(dt);            
  35.                    HttpRuntime.Cache.Insert("dt", dt, scd);              
  36.                     sqlCon.Close();
  37.                 }
  38.             }
  39.             GridView1.DataSource = dt;
  40.             GridView1.DataBind();         
  41.         }      
  42.     }
  43. }

[csharp] view plaincopy

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Web; 
  5. using System.Web.UI; 
  6. using System.Web.UI.WebControls; 
  7. using System; 
  8. using System.Configuration; 
  9. using System.Collections.Generic; 
  10. using System.Data; 
  11. using System.Data.SqlClient; 
  12. using System.Web; 
  13. using System.Web.UI; 
  14. using System.Web.UI.WebControls; 
  15. using System.Web.Caching; 
  16. namespace WebTest2 
  17. public partial class _Default : System.Web.UI.Page 
  18.     { 
  19. protected void Page_Load(object sender, EventArgs e) 
  20.         {           
  21.             DataTable dt = HttpRuntime.Cache["dt"] as DataTable; 
  22. if (dt == null) 
  23.             { 
  24. using (SqlConnection sqlCon = new SqlConnection(WebConfigHelper.ConnectionString_SQL2005)) 
  25.                 { 
  26.                     sqlCon.Open(); 
  27.                     SqlCommand sqlCmd = new SqlCommand(); 
  28.                     sqlCmd.Connection = sqlCon; 
  29.                     sqlCmd.CommandText = "select col2 from dbo.TableTest"; 
  30.                     dt = new DataTable(); 
  31.                 SqlCacheDependency scd = new SqlCacheDependency(sqlCmd);     
  32.                     SqlDataAdapter sda = new SqlDataAdapter(sqlCmd);                    
  33.                     sda.Fill(dt);             
  34.                    HttpRuntime.Cache.Insert("dt", dt, scd);               
  35.                     sqlCon.Close(); 
  36.                 } 
  37.             } 
  38.             GridView1.DataSource = dt; 
  39.             GridView1.DataBind();          
  40.         }       
  41.     } 

     很明显通知模式,配置文件不需要任何特殊处理,数据库中也没有增加表AspNet_SqlCacheTablesForChangeNotification和Trigger,性能也比轮询模式好的多。只要数据库中数据有改变,cache中的对应数据就会清空,基本上是实时的,不像轮询模式由pollTime决定。

通知模式需要注意的时,一定要在创建数据库之前,把数据库配置管理中的tcp/ip的那个配置改为able,否则就会出项很诡异的错误,能发出通知,但客户端就是不能收到,无论数据库中的数据怎样改变,读取的数据始终是缓存中的数据,但把tcp/ip的那个配置改为able后,再创建的数据库就可以,而且好像只有首次配置才会出现,当再次把able改为diable时在创建数据库,再改为able时,就不会出现了,很奇怪。整整折腾了三天,才发现此问题!!

  另外使用windows身份认证创建的数据库也有可能导致此问题,具体原因不明。所以应该使用SQL身份认证创建数据库,不要使用windows身份认证创建数据库。很奇怪后来在测试时,使用windows身份认证创建数据库又可以了,所以具体原因目前不知道。

原因参考

http://www.cnblogs.com/rickie/archive/2006/12/21.html

另外通知模式的查询语句也有一定的要求,这一定要注意。参考支持的 SELECT 语句

存储过程不能包含SET NOCOUNT ON,WITH(NOLOCK),否者数据不能缓存到Cache,每次都是重新读取数据库,不管数据有没有改变。

通知模式的延时估计有几百毫秒,也就是说,在更新数据库后,立即读取Cache数据不是空的,但我测试一秒后就为空了,不会影响实际使用的,但对单元测试会有影响,一定要Thread.sleep(1000),否则单元测试不能通过。

参考文章

SQL数据缓存依赖

SQL Server2005实现数据库缓存依赖的实现步骤

Sql Server 2005/2008 SqlCacheDependency查询通知的使用总结

SqlCacheDependency 类

使用 SqlCacheDependency 类在 ASP.NET 中缓存

启用查询通知

诡异问题详细信息

数据sqlcachedependency轮询功能配置方法

caching 的 sqlCacheDependency 的 databases 元素(ASP.NET 设置架构)

caching 的 sqlCacheDependency 元素(ASP.NET 设置架构)

caching 的 database 的 add 元素(ASP.NET 设置架构

SQL Server 中的查询通知 (ADO.NET)

为通知创建查询

我在这篇文章的末尾分享一下我们最近做项目中关于通知模式中应用的一些经验:

我们有一个复杂的查询语句写在一个存储过程里,但是这是通知模式所不支持的sql语句,所以我们HardCode了一段查询两张表的简单查询语句去达到通知模式中的监控两张表,然后在注册在cache中,下面是代码:

[csharp] view plaincopy

  1. 对两张表监控的SqlCacheDependency的应用  
  2. public const string SqlDependencyCacheSql = "SELECT id FROM dbo.Products;SELECT id FROM dbo.ExpiredProducts;"; 
  3. public static SqlCacheDependency GetSqlCacheDependency() 
  4.         { 
  5.             SqlCacheDependency sqlCacheDependency = null; 
  6. using (SqlConnection sqlCon = new SqlConnection(dbConnectionString)) 
  7.             { 
  8.                 SqlCommand sqlCmdCache = new SqlCommand(SqlDependencyCacheSql, sqlCon); 
  9.                 sqlCacheDependency = new SqlCacheDependency(sqlCmdCache); 
  10. try
  11.                 { 
  12.                     sqlCon.Open(); 
  13.                     sqlCmdCache.ExecuteNonQuery(); 
  14.                 } 
  15. catch
  16.                 { 
  17. throw; 
  18.                 } 
  19.             } 
  20. return sqlCacheDependency; 
  21.         } 
  22. public static Dictionary<string, Product> Products 
  23.         { 
  24. get
  25.             { 
  26. if (HttpRuntime.Cache[CacheAllProduct] == null) 
  27.                 { 
  28.                     SqlCacheDependency sqlCacheDependency = BrandPartnerDataAccess.GetSqlCacheDependency(); 
  29.                     DataTable dt = DataAccess.GetAllProduct(); 
  30.                     HttpRuntime.Cache.Insert(CacheAllProduct, ConvertToProductsDictionary(dt), sqlCacheDependency); 
  31.                 } 
  32. return HttpRuntime.Cache[CacheAllProduct] as Dictionary<string, Product>; 
  33.             } 
  34.         } 

 

原文地址:http://blog.csdn.net/cai15191466621/article/details/7493308

© 著作权归作者所有

随智阔
粉丝 21
博文 687
码字总数 705350
作品 0
海淀
程序员
私信 提问
SQL数据缓存依赖 [SqlServer | Cache | SqlCacheDependency ]

一、SQL SERVER 7.0/2000和SQL SERVER 2005的简介及比较 1.1 SQL SERVER 7.0/2000 SQL SERVER 7.0/2000没有提供内置的支持数据缓存依赖的功能,所以只能通过采用添加特定数据库表、触发器等方...

walb呀
2017/12/07
0
0
SQL Server里简单参数化的痛苦

一般来说,如果你处理所谓的安全执行计划(Safe Execution Plan),SQL Server自动参数化你的SQL语句:不管提供的参数值,查询总必须通向一样的执行计划。如果你的执行计划里有书签查找,这就...

范大脚脚
2017/11/14
0
0
Asp.net缓存简介

概述 缓存学术一些的解释是”将常用数据放入易于读取的地方以提高性能”。而对于Asp.net来说,需要被缓存的对象多种多样,包括从数据库中提取出来的数据,以及aspx页面生成的静态页,甚至是编...

范大脚脚
2017/12/14
0
0
Microsoft .NET Pet Shop 4 架构与技术分析

1.项目概述与架构分析微软刚推出了基于ASP.NET 2.0下的Pet Shop 4, 该版本有了一个全新的用户界面。是研究ASP.NET 2.0的好范例啊,大家都知道,一直以来,在.NET和Java之间争论不休,到底使...

晨曦之光
2012/03/09
124
0
ASP.NET状态管理之六(缓存Cache)

ASP.NET 为您提供了一个强大的、便于使用的缓存机制,用于将需要大量服务器资源来创建的对象存储在内存中。缓存这些类型的资源会大大改进应用程序的性能。 缓存是由 Cache 类实现的;缓存实例...

范大脚脚
2017/12/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

parseint和isNaN用法

本文转载于:专业的前端网站➭parseint和isNaN用法 <!doctype html><html><head><meta charset="utf-8"><title>无标题文档</title></head><body><script> var a='12'; alert......

前端老手
14分钟前
2
0
Kylin 精确去重在用户行为分析中的妙用

作者:史少锋,Apache Kylin committer & PMC,2019/10/11 在上次文章《如何在 1 秒内做到大数据精准去重》中,我们介绍了 Apache Kylin 为什么要支持大数据集上的精确去重,以及基于 Bitmap...

ApacheKylin
25分钟前
1
0
学习记录(二) es6基本语法(rest参数,模板化,axios模块,拦截器)

日常学习记录 模块化:把一个大文件分成多个小文件,按照一定规范进行拼接 es5写法: 导出:module.exports = 数据 导入:require("路径") /路径未添加后缀名时 //默认添加.js //把路径作为文件名...

Pole丶逐
29分钟前
2
0
以程序员的角度怎么购买一台「性价比高的电视」

前俩天有小伙伴在我的文章下留言,说能否把 【国内电视机都介绍一下】,今天我已在TV端开发多年的程序员的角度。谈谈已程序员的角度如何购买一台性价比高的电视。 国内大的电视机品牌介绍 长...

我们都很努力着
32分钟前
1
0
PhotoShop 色调:理解直方图/RGB通道信息

一、直方图:图表的形式,展示图像像素分布的情况 1.平均值:表示平均亮度 2.标准偏差值:表示亮度值范围内的中间值 3.像素: 表示用于计算直方图的像素总数 4.色阶:显示指针下面的区域亮度...

东方墨天
38分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部