SQL server数据缓存依赖
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
- <?xmlversion="1.0"?>
- <configuration>
- <connectionStrings>
- <add name="PubsConnectionString"connectionString="Data Source=10.32.153.165; Initial Catalog=pubs;uid=sa;pwd=q1w2e31@;"providerName="System.Data.SqlClient"/>
- </connectionStrings>
- <system.web>
- <compilationdebug="true"targetFramework="4.0"/>
- <caching>
- <sqlCacheDependencyenabled ="true"pollTime ="1000">
- <databases>
- <!--name:必需的 String 属性。 要添加到配置集合中的 SqlCacheDependencyDatabase 对象的名称。
- 此名称用作 @ OutputCache 指令上 SqlDependency 属性的一部分。
- pollTime:设置 SqlCacheDependency 轮询数据库表以查看是否发生更改的频率(以毫秒计算)。这儿是一个测试,所以设为10秒,请加大此值
- connectionStringName 必选的 String 特性。为数据库设置连接字符串名称。 在 connectionStrings 元素(ASP.NET 设置架构) 配置节中引用连接字符串。-->
- <addname="Pubs"connectionStringName = "PubsConnectionString"/>
- </databases>
- </sqlCacheDependency>
- </caching>
- </system.web>
- </configuration>
[html] view plaincopy
- <?xml version="1.0"?>
- <configuration>
- <connectionStrings>
- <add name="PubsConnectionString" connectionString="Data Source=10.32.153.165; Initial Catalog=pubs;uid=sa;pwd=q1w2e31@;" providerName="System.Data.SqlClient" />
- </connectionStrings>
- <system.web>
- <compilation debug="true" targetFramework="4.0" />
- <caching>
- <sqlCacheDependency enabled = "true" pollTime = "1000" >
- <databases>
- <!--name:必需的 String 属性。 要添加到配置集合中的 SqlCacheDependencyDatabase 对象的名称。
- 此名称用作 @ OutputCache 指令上 SqlDependency 属性的一部分。
- pollTime:设置 SqlCacheDependency 轮询数据库表以查看是否发生更改的频率(以毫秒计算)。这儿是一个测试,所以设为10秒,请加大此值
- connectionStringName 必选的 String 特性。为数据库设置连接字符串名称。 在 connectionStrings 元素(ASP.NET 设置架构) 配置节中引用连接字符串。-->
- <add name="Pubs" connectionStringName = "PubsConnectionString" />
- </databases>
- </sqlCacheDependency>
- </caching>
- </system.web>
- </configuration>
注意:connectionStrings,和caching两节的关系,caching节的connectionStringName需要和connectionStrings中的name对应的。
1.3 SqlCacheDependencyAdmin使用
[csharp] view plaincopy
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.Caching;
- using System.Configuration;
- using System.Data.SqlClient;
- namespace TestWebSqlCacheDependency
- {
- public partial class _Default : System.Web.UI.Page
- {
- string key = "model_type";
- protected void Page_Load(object sender, EventArgs e)
- {
- TextBox1.Text = test();// test();
- }
- private string test()
- {
- //从缓存中取值
- string model = null;
- if (HttpRuntime.Cache[key] !=null)
- {
- model = HttpRuntime.Cache[key].ToString();
- }
- if (model ==null)
- {
- //取数据
- model = getDBValue();
- //启用更改通知
- SqlCacheDependencyAdmin.EnableNotifications(
- ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString);
- //连接到 SQL Server 数据库并为 SqlCacheDependency 更改通知准备数据库表
- SqlCacheDependencyAdmin.EnableTableForNotifications(
- ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString,"TableTest");//第二个参数是要监控的表名称
- //制定缓存策略
- SqlCacheDependency scd = new SqlCacheDependency("Pubs","TableTest");
- //注意此处的Pubs需要要配置文件的caching节下的databases节下的name对应,而不是随便写的,目前个人测试的结论就是这样。第二个参数是要监控的表名称
- //插入缓存
- HttpRuntime.Cache.Insert(key, model, scd);
- }
- return model;
- }
- private string getDBValue()
- {
- SqlConnection cn = newSqlConnection(ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString);
- cn.Open();
- SqlCommand cd = cn.CreateCommand();
- cd.CommandText = " select top 1 TableTest.col2 from TableTest ";
- object o = cd.ExecuteScalar();
- cn.Close();
- if (o != null)
- {
- return o.ToString();
- }
- return null;
- }
- }
- }
[csharp] view plaincopy
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.Caching;
- using System.Configuration;
- using System.Data.SqlClient;
- namespace TestWebSqlCacheDependency
- {
- public partial class _Default : System.Web.UI.Page
- {
- string key = "model_type";
- protected void Page_Load(object sender, EventArgs e)
- {
- TextBox1.Text = test();// test();
- }
- private string test()
- {
- //从缓存中取值
- string model = null;
- if (HttpRuntime.Cache[key] != null)
- {
- model = HttpRuntime.Cache[key].ToString();
- }
- if (model == null)
- {
- //取数据
- model = getDBValue();
- //启用更改通知
- SqlCacheDependencyAdmin.EnableNotifications(
- ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString);
- //连接到 SQL Server 数据库并为 SqlCacheDependency 更改通知准备数据库表
- SqlCacheDependencyAdmin.EnableTableForNotifications(
- ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString, "TableTest");//第二个参数是要监控的表名称
- //制定缓存策略
- SqlCacheDependency scd = new SqlCacheDependency("Pubs", "TableTest");
- //注意此处的Pubs需要要配置文件的caching节下的databases节下的name对应,而不是随便写的,目前个人测试的结论就是这样。第二个参数是要监控的表名称
- //插入缓存
- HttpRuntime.Cache.Insert(key, model, scd);
- }
- return model;
- }
- private string getDBValue()
- {
- SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["PubsConnectionString"].ConnectionString);
- cn.Open();
- SqlCommand cd = cn.CreateCommand();
- cd.CommandText = " select top 1 TableTest.col2 from TableTest ";
- object o = cd.ExecuteScalar();
- cn.Close();
- if (o != null)
- {
- return o.ToString();
- }
- return null;
- }
- }
- }
轮询模式的实质,就是在数据库中多了一个表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
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Security;
- using System.Web.SessionState;
- using System.Data.SqlClient;
- using System.Web.Caching;
- namespace WebTest2
- {
- public class Global : System.Web.HttpApplication
- {
- void Application_Start(object sender, EventArgs e)
- {
- #region SQL2005
- SqlDependency.Start(ConnectionString_SQL2005);//推荐将这段代码加到Global.asax的Application_Start方法中
- #endregion
- }
- void Application_End(object sender, EventArgs e)
- {
- SqlDependency.Stop(ConnectionString_SQL2005);
- }
- }
- }
[csharp] view plaincopy
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Security;
- using System.Web.SessionState;
- using System.Data.SqlClient;
- using System.Web.Caching;
- namespace WebTest2
- {
- public class Global : System.Web.HttpApplication
- {
- void Application_Start(object sender, EventArgs e)
- {
- #region SQL2005
- SqlDependency.Start(ConnectionString_SQL2005);//推荐将这段代码加到Global.asax的Application_Start方法中
- #endregion
- }
- void Application_End(object sender, EventArgs e)
- {
- SqlDependency.Stop(ConnectionString_SQL2005);
- }
- }
- }
调试时注意一定要运行SqlDependency.Start()这句,否则就会出错,所以测试时不要使用预览模式。由于vs会启动WebDev.WebServer40.EXE ,导致SqlDependency.Start()可能就没有运行,所以调试时一定要把VS启动的WebDev.WebServer40.EXE的前一次模拟服务停止了,使vs重新启动WebDev.WebServer40.EXE,并运行SqlDependency.Start()。
2.3 使用
[csharp] view plaincopy
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System;
- using System.Configuration;
- using System.Collections.Generic;
- using System.Data;
- using System.Data.SqlClient;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.Caching;
- namespace WebTest2
- {
- public partial class _Default : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- DataTable dt = HttpRuntime.Cache["dt"]as DataTable;
- if (dt == null)
- {
- using (SqlConnection sqlCon =newSqlConnection(WebConfigHelper.ConnectionString_SQL2005))
- {
- sqlCon.Open();
- SqlCommand sqlCmd = new SqlCommand();
- sqlCmd.Connection = sqlCon;
- sqlCmd.CommandText = "select col2 from dbo.TableTest";
- dt = new DataTable();
- SqlCacheDependency scd = new SqlCacheDependency(sqlCmd);
- SqlDataAdapter sda = new SqlDataAdapter(sqlCmd);
- sda.Fill(dt);
- HttpRuntime.Cache.Insert("dt", dt, scd);
- sqlCon.Close();
- }
- }
- GridView1.DataSource = dt;
- GridView1.DataBind();
- }
- }
- }
[csharp] view plaincopy
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System;
- using System.Configuration;
- using System.Collections.Generic;
- using System.Data;
- using System.Data.SqlClient;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.Caching;
- namespace WebTest2
- {
- public partial class _Default : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- DataTable dt = HttpRuntime.Cache["dt"] as DataTable;
- if (dt == null)
- {
- using (SqlConnection sqlCon = new SqlConnection(WebConfigHelper.ConnectionString_SQL2005))
- {
- sqlCon.Open();
- SqlCommand sqlCmd = new SqlCommand();
- sqlCmd.Connection = sqlCon;
- sqlCmd.CommandText = "select col2 from dbo.TableTest";
- dt = new DataTable();
- SqlCacheDependency scd = new SqlCacheDependency(sqlCmd);
- SqlDataAdapter sda = new SqlDataAdapter(sqlCmd);
- sda.Fill(dt);
- HttpRuntime.Cache.Insert("dt", dt, scd);
- sqlCon.Close();
- }
- }
- GridView1.DataSource = dt;
- GridView1.DataBind();
- }
- }
- }
很明显通知模式,配置文件不需要任何特殊处理,数据库中也没有增加表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 Server 2005/2008 SqlCacheDependency查询通知的使用总结
使用 SqlCacheDependency 类在 ASP.NET 中缓存
caching 的 sqlCacheDependency 的 databases 元素(ASP.NET 设置架构)
caching 的 sqlCacheDependency 元素(ASP.NET 设置架构)
caching 的 database 的 add 元素(ASP.NET 设置架构
我在这篇文章的末尾分享一下我们最近做项目中关于通知模式中应用的一些经验:
我们有一个复杂的查询语句写在一个存储过程里,但是这是通知模式所不支持的sql语句,所以我们HardCode了一段查询两张表的简单查询语句去达到通知模式中的监控两张表,然后在注册在cache中,下面是代码:
[csharp] view plaincopy
- 对两张表监控的SqlCacheDependency的应用
- public const string SqlDependencyCacheSql = "SELECT id FROM dbo.Products;SELECT id FROM dbo.ExpiredProducts;";
- public static SqlCacheDependency GetSqlCacheDependency()
- {
- SqlCacheDependency sqlCacheDependency = null;
- using (SqlConnection sqlCon = new SqlConnection(dbConnectionString))
- {
- SqlCommand sqlCmdCache = new SqlCommand(SqlDependencyCacheSql, sqlCon);
- sqlCacheDependency = new SqlCacheDependency(sqlCmdCache);
- try
- {
- sqlCon.Open();
- sqlCmdCache.ExecuteNonQuery();
- }
- catch
- {
- throw;
- }
- }
- return sqlCacheDependency;
- }
- public static Dictionary<string, Product> Products
- {
- get
- {
- if (HttpRuntime.Cache[CacheAllProduct] == null)
- {
- SqlCacheDependency sqlCacheDependency = BrandPartnerDataAccess.GetSqlCacheDependency();
- DataTable dt = DataAccess.GetAllProduct();
- HttpRuntime.Cache.Insert(CacheAllProduct, ConvertToProductsDictionary(dt), sqlCacheDependency);
- }
- return HttpRuntime.Cache[CacheAllProduct] as Dictionary<string, Product>;
- }
- }
原文地址:http://blog.csdn.net/cai15191466621/article/details/7493308
SQL server数据缓存依赖的更多相关文章
- SQL Server SqlCacheDependency 缓存依赖
SQL server数据缓存依赖有两种实现模式,轮询模式,通知模式. 1 轮询模式实现步骤 此模式需要SQL SERVER 7.0/2000/2005版本以上版本都支持 主要包含以下几步: 1. ...
- SQL Server 数据缓存
引言 SQL Server通过一些工具来监控数据,其中之一的方法就是动态管理管理视图(DMV). 常规动态服务器管理对象 dm_db_*:数据库和数据库对象 dm_exec_*:执行用户代码和关联的连 ...
- SQL数据缓存依赖总结
以前只听过SQL server数据缓存依赖,但一直没使用,由于项目需要,才研究了一番,发现了一个很诡异的问题,竟然是一个操作顺序问题导致的. SQL server数据缓存依赖有两种实现模式,轮询模式, ...
- SQL SERVER 2000 & SQL SERVER 2005 数据缓存依赖
一.SQL SERVER 7.0/2000和SQL SERVER 2005的简介及比较 1.1 SQL SERVER 7.0/2000 SQL SERVER 7.0/2000没有提供内置的支持 ...
- cache应用(asp.net 2.0 SQL数据缓存依赖 [SqlCacheDependency ] )
Asp.net 2.0 提供了一个新的数据缓存功能,就是利用sql server2005 的异步通知功能来实现缓存 1.首先在sqlserver2005 中创建一个test的数据库. 在SQL Ser ...
- SQL数据缓存依赖 [SqlServer | Cache | SqlCacheDependency ]
前言 本文主要是对<ASP.NET 2.0开发指南>——<数据缓存>章节内容的提取并略有补充. 参考资料 1. <ASP.NET 2.0开发指南> 2. ...
- 我用ASP.NET缓存之SQL数据缓存依赖(SqlCacheDependency)
[名词解释] 缓存(Cache)依赖,大白话解释就是缓存是否更新依赖于其它Object.那么SqlCacheDependency指的就是Cache的数据更新依赖于SQL Server数据库表的变化( ...
- 对MySql查询缓存及SQL Server过程缓存的理解及总结
一.MySql的Query Cache 1.Query Cache MySQL Query Cache是用来缓存我们所执行的SELECT语句以及该语句的结果集.MySql在实现Query Cache的 ...
- [SQL]SQL Server数据表的基础知识与增查删改
SQL Server数据表的基础知识与增查删改 由张晨辉(学生) 于19天 前发表 | 阅读94次 一.常用数据类型 .整型:bigint.int.smallint.tinyint .小数:decim ...
随机推荐
- c++ 文件读写模板
#include <fstream> using namespace std; int main() { ifstream fin("in.txt"); ofstrea ...
- eclipse中新建jni工程
1.什么是NDK 网上很多不多说,全称是Android Native Developer Kit,是一个工具合集,我理解可以把c/c++打包成.so文件 这是目录结构,要用到指令ndk-build 需 ...
- linux笔记:shell基础-bash基本功能
历史命令的调用: 命令和文件补全(如果当前有多个可选的补全,则按2次tab键,可以列出所有的可选项): 命令别名: 让别名永久生效: 删除别名: bash常用快捷键: 标准输入输出: 输出重定向: 输 ...
- 关于JAVA EE项目在WEB-INF目录下的jsp页面如何访问WebRoot中的CSS和JS文件
找了这么久资料,总算解决了 感谢博客园:http://www.cnblogs.com/xsht/p/5275081.html 感谢百度:http://zhidao.baidu.com/link?url ...
- vue.js学习笔记之v-bind,v-on
v-bind 指令用于响应地更新 HTML 特性 形式如:v-bind:href 缩写为 :href; v-on 指令用于监听DOM事件 形式如:v-on:click 缩写为 @clic ...
- WPF CAL 计算器
界面最终结果: 下载地址:https://skydrive.live.com/redir?resid=25C3908AA2038BDB!148&authkey=!ADR71XdB04LipYE
- JavaScipt 源码解析 css选择器
css1-css3提供了很多选择器,总得来说分为几大类: 群组选择器:逗号"," 简单选择器:ID,标签,类,属性,通配符 关系选择器:孩子,后代,兄弟,相邻 伪类选择器:动作伪类 ...
- javascript 特殊的一些知识
基础知识 1.注释/**/ 块注释,与正则表达式有冲突,不安全. 2.js数字类型只有一个,即为64位的浮动值 3.NaN是一个数值,他不能产生正常结果的运算结果.NaN不等于任何值,包括它自己.is ...
- C# 跨线程调用控件
在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应. 同时我们又需要在工作线程中更新UI界面上的控件, 下面介绍几种常用的方法 阅读目录 线程间操作无效 第一种办法:禁 ...
- 连接到CentOS(Linux)服务器ssh、mysql缓慢
现象: 服务器163与服务器164在同一机柜,双绞线直接连接,从办公室或者服务器163去连机服务器164的ssh.mysql均缓慢,让机房人员查了,无果.而164却正常. 最后发现两个机器/etc/r ...