源码下载地址:http://download.csdn.net/detail/wuziteng2006/6228703
这两个版本的使用背景完全不一样。第一个版本是为了获得异常信息,因为程序抛出的异常、错误都存在某个数据表中,所以我的工具只要监控这张表,一旦发现有新数据,就直接发邮件通知相关人员;而第二个版本,不仅是监控一张表,而是数据库的所有表;因为程序调用了大量的Web Service,大部分都是其他Team提供的API,我们对这些API具体做了哪些事情,对哪个数据库的哪张表做了Insert,Update,Delete操作都不了解,平时只能手动去查。当然,我们通过SQL Profile也可以了解程序后台的SQL处理,但是对于存储过程来说,SQL Profile并不直观,它会显示exec了某个存储过程,而后我们还得费心去阅读代码,才能真切地了解这个存储过程做了哪些动作...因此,为了更好地理解API,‘数据库变更通知II’我也叫它DBMonitor就应运而生了。
遇到的问题
1. TimeOut 超时异常
跟第一版一样,数据表变更通知的核心是SqlDependency,所以需要对监控的数据库设置Service Broker,如:
ALTER DATABASE SampleDb SET ENABLE_BROKER
如果遇到了TimeOut异常,就关闭SQL Server的Agent代理功能,再执行语句。在确认Broker状态为Enable之后可启动Agent。
SELECT NAME, IS_BROKER_ENABLED FROM SYS.DATABASES
BTW, 网上有人建议用sqlCacheDependency或是AggregateCacheDependency来取代SqlDependency;前两者我没试过,反正SqlDependency就用着挺好的
2. The Service Broker in database "DACustomerDB" cannot be enabled because there is already an enabled Service Broker with the same ID
项目的测试环境非常复杂,很多核心数据库都有两个Partition,比如Subscription1和Subscription2。举个例子,我们在测试机上调用CreateCustomer接口,它会随机在Partition中两者择其一,要么在Subscription1上插入数据,要么影响了Subscription2。所以,如果要了解CreateCustomer,我们要把Subscription1和2都设置Broker。但如果Subscription1已经设置了,那么使用SET ENABLE_BROKER对Subscription2进行操作时,会出现上述错误。
解决办法是:
Alter database DACustomerDB set NEW_BROKER
详见http://www.symantec.com/business/support/index?page=content&id=TECH181848
3.
INSERT failed because the following SET options have incorrect settings: 'QUOTED_IDENTIFIER'. Verify that SET options are correct for use with indexed views and/or indexes on computed columns and/or filtered indexes and/or query notifications and/or XML data type methods and/or spatial index operations.可能是SQL Server本身Query Notification设计的原因,如果存储过程的QUOTED_IDENTIFIER设置为OFF,就无法捕获到它对数据表造成的变更。为了解决这个问题,我只得把存储过程的内容导出,把QUOTED_IDENTIFIER设置为ON。当然,设置为ON之前,我已经测试过,这样改动不会影响程序功能。以下是实现方法:
public int HackSP4Notification()
{
IList<string> StoreProce = new List<string>();
StringBuilder strTemp = new StringBuilder();
string strSQL = @"
select b.[name],a.[text] , replace(a.[text],'CREATE PROCEDURE','ALTER PROCEDURE') as NewText from syscomments A inner join sysobjects B on A.ID=B.ID
where b.xtype='P'
and name in (
select s.name from sys.objects s
where
OBJECTPROPERTY(s.object_id,'ExecIsQuotedIdentOn')=0
)
";
try
{
DataTable dt = this.GetDataTable(strSQL);
//Get all of Store_Procedure Name
var spNames = (from row in dt.AsEnumerable() select row.Field<string>("Name")).Distinct();
foreach (var sp in spNames) {
StoreProce.Add(sp);
//Query the detailed script by sp name
var spText = from r in dt.AsEnumerable()
where r.Field<string>("name") == sp
select r.Field<string>("NewText");
//Insert the sp text into a string
foreach (var subText in spText) {
strTemp.Append(subText.ToString());
}
//Execute the sql command to ensure "SET QUOTED_IDENTIFIER ON"
this.ExecuteSQLStmt(strTemp.ToString());
strTemp.Clear();
}
}
catch (Exception)
{
throw new Exception(strTemp.ToString());
}
return StoreProce.Count;
}