CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
英特尔®游戏设计大赛100美元现金周周送 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  VC/MFC >  数据库

程序如何得到“SQL数据库的数据被修改”的即时通知??

楼主huangbeyond(校园人渣)2003-09-02 22:40:46 在 VC/MFC / 数据库 提问

有一个EXE程序在运行,现在试图使用它来监视SQL数据库内某个指定的表的数据变化信息:当有其它用户修改了数据库数据(比如ASP等),该EXE程序能够即时地得到通知,并在第一时间内可以对修改后的数据进行处理。  
   
  SQL数据库有相关的接口,或者回调机制吗?(该EXE使用标准ODBC接口来访问SQL数据库)  
   
  不知道如何实现,盼高手能提供一些经验。  
   
  谢谢!! 问题点数:200、回复次数:16Top

1 楼huangbeyond(校园人渣)回复于 2003-09-02 22:40:58 得分 0

先顶一次。Top

2 楼small_wei(small)回复于 2003-09-03 01:27:13 得分 50

对要监控的表做一个触发器(可以是insert   ,update   etc..),在触发器中调用一DLL程序,将相关的数据通过消息发送给你的程序就行了。  
   
  在存储过程中调用外部的动态连接库(MS   SQL   Server7.0/2000环境)  
   
  问题的提出:  
  一般我们要根据数据库的纪录变化时,进行某种操作。我们习惯的操作方式是在程序中不停的查询表,判断是否有新纪录。这样耗费的资源就很高,如何提高这种效率,我想在表中创建触发器,在触发器中调用外部动态连接库通过消息或事件通知应用程序就可实现。而master的存储过程中最好能调用外部的动态连接库,我们在触发器中调用master的存储过程即可。  
   
   
  说明:VC6需要安装较新的Platform   SDK才能顺利编译本代码,VC.Net可以直接编译本代码。另外还需要连接Opends60.lib  
  为了使没有较新Platform   SDK的朋友也能编译本例子,已经将VC.Net中的Srv.h和Opends60.lib放到压缩包中  
   
  程序实现:  
  我们来实现一个存储过程中调用外部的dll(storeproc.dll)的函数SetFileName和addLine。  
   
  存储过程如下(需放到master库中):   CREATE   PROCEDURE   sp_testdll   AS  
   
  exec   sp_addextendedproc   'SetFileName',   'storeproc.dll' --声明函数  
  exec   sp_addextendedproc   'addLine',   'storeproc.dll'  
   
  declare   @szFileName   varchar(200)  
  declare   @szText   varchar(200)  
  declare   @rt   int  
   
  Select   @szFileName   =   'c:\welcome.txt'  
   
  EXEC   @rt   =   SetFileName   @szFileName --调用SetFileName函数,参数为--szFileName;  
  if   @rt   =   0  
  begin  
  select   @szText   =   'welcome   01'  
  Exec   @rt   =   addLine   @szText --调用addLine  
  select   @szText   =   'welcome   02'  
  Exec   @rt   =   addLine   @szText  
   
  end  
  exec   sp_dropextendedproc   'SetFileName'  
  exec   sp_dropextendedproc   'addLine'  
   
  dbcc   SetFileName(free)  
  dbcc   addLine(free)  
   
  动态连接库的实现:这种动态连接库和普通的有所不同。该动态连接库要放入SQL的执行目录下,或直接放到Window的System32目录下,并重起SQL-Server   #include   <windows.h>  
  #include   <srv.h> //要加入这个.h文件  
   
  #define   XP_NOERROR             0  
  #define   XP_ERROR                 1  
   
  #ifndef   _DEBUG  
  #define   _DEBUG  
  #endif  
   
  char   szFileName[MAX_PATH+1];  
   
  void   WriteInfo(const   char   *   str);  
   
  extern   "C"   SRVRETCODE   WINAPI   SetFileName(SRV_PROC*   pSrvProc)  
  {  
  WriteInfo("SetFileName   start");  
  int   paramCount   =   srv_rpcparams(pSrvProc);  
  if   (paramCount   !=   1){  
  WriteInfo("Param   Err   start");  
  return   XP_ERROR;  
  }  
   
  BYTE bType;  
  unsigned   long cbMaxLen;  
  unsigned   long cbActualLen;  
  BOOL fNull;  
   
  int   ret   =   srv_paraminfo(pSrvProc,   1,   &bType,   &cbMaxLen,   &cbActualLen,  
                  NULL,   &fNull);  
  if   (cbActualLen){  
  ZeroMemory(szFileName,   MAX_PATH+1);  
  memcpy(szFileName,   srv_paramdata(pSrvProc,   1),   cbActualLen);  
  WriteInfo("Set   filename   ok");  
  return   (XP_NOERROR);  
  }  
  else   {  
  WriteInfo("Set   filename   param   failed");  
  return   XP_ERROR;  
  }  
  }  
   
  extern   "C"   SRVRETCODE   WINAPI   addLine(SRV_PROC*   pSrvProc)  
  {  
  WriteInfo("addline   start");  
  int   paramCount   =   srv_rpcparams(pSrvProc);  
  if   (paramCount   !=   1){  
  WriteInfo("addline   param   err");  
  return   XP_ERROR;  
  }  
   
  BYTE                 bType;  
  unsigned   long cbMaxLen;  
  unsigned   long cbActualLen;  
  BOOL fNull;  
  bool rt   =   false;  
   
  int   ret   =   srv_paraminfo(pSrvProc,   1,   &bType,   &cbMaxLen,   &cbActualLen,  
                  NULL,   &fNull);  
   
  if   (cbActualLen){  
  int   n;  
  char   srt[3]   =   {0x0d,   0x0a,   0};  
   
  char   *   c   =   new   char[cbActualLen   +   3];  
  if   (!c)return   XP_ERROR;  
   
  ZeroMemory(c,   cbActualLen   +   3);  
  memcpy(c,   srv_paramdata(pSrvProc,   1),   cbActualLen);  
  memcpy(c+cbActualLen,   srt,   3);  
   
  HANDLE   hf   =   CreateFile(szFileName,   GENERIC_WRITE,   FILE_SHARE_WRITE|FILE_SHARE_READ,   NULL,    
                      OPEN_ALWAYS,   0,   NULL);  
  if   (hf   ==   INVALID_HANDLE_VALUE){  
  WriteInfo("addline   create   file   err   ");  
  delete   []c;  
  return   XP_ERROR;  
  }  
   
  WriteInfo("addline   create   file   ok   ");  
  DWORD   dwWt;  
  n   =   strlen(c);  
  SetFilePointer(hf,   0,   NULL,   FILE_END);  
  if   (WriteFile(hf,   c,   n,   &dwWt,   NULL)   &&   dwWt   ==   n)  
  {  
  WriteInfo("addline   write   file   ok   ");  
  rt   =   true;  
  }  
  delete   []c;  
  CloseHandle(hf);  
  }  
  return   rt   ?   XP_NOERROR:XP_ERROR;  
  }  
   
  inline   void   WriteInfo(const   char   *   str){  
          #ifdef   _DEBUG  
  char   srt[3]   =   {0x0d,   0x0a,   0};  
  HANDLE   hf   =   CreateFile("c:\\storeproc.log",   GENERIC_WRITE,   FILE_SHARE_WRITE|FILE_SHARE_READ,   NULL,    
                      OPEN_ALWAYS,   0,   NULL);  
  if   (hf   !=   INVALID_HANDLE_VALUE){  
  SetFilePointer(hf,   0,   NULL,   FILE_END);  
  DWORD   dwWt;  
  WriteFile(hf,   str,   strlen(str),   &dwWt,   NULL);  
  WriteFile(hf,   srt,   strlen(srt),   &dwWt,   NULL);  
  CloseHandle(hf);  
  }  
  else   {  
  MessageBox(NULL,   "Write   info   err",   "Message",   MB_OK|MB_ICONINFORMATION);  
  }  
  #endif  
  }  
   
  BOOL   WINAPI   DllMain(HINSTANCE   hinstDLL,DWORD   fdwReason,LPVOID   lpReserved)  
  {  
  return   TRUE;  
  }  
   
  编译完成后,把动态链接库放到WINNT/System32目录下,启动SQL   Server。我们可以打开SQL   Server   Query   Analyzer调用存储过程sp_testdll以测试其运行是否正确。  
   
  具体可参考SQL-Server的在线帮助。  
  Top

3 楼njtlxm(似是故人来)回复于 2003-09-03 09:04:53 得分 50

用SQL   里的存储过程调用外部的exe或者bat也一样,调用的时候传入修改数据的关键参数(比如:表名+主键)就可以了。Top

4 楼cdwy411(VC$ORACLE)回复于 2003-09-03 10:34:58 得分 0

做个触发器吧!!!  
  一有变动,自动触发函数处理!!Top

5 楼r3000()回复于 2003-09-03 11:50:19 得分 50

触发器,DLL什么得都是笨的不能再笨的办法,定义触发器会严重影响效率。  
   
  以下纯属猜测或者说提醒,本人并没有实践。  
   
  实际上表的插入、删除、更新等的变化,SQL   Sever内部都有记载(系统表、日志)  
  ,只要你的EXE不断监视此记载即可。  
   
   
   
   
  Top

6 楼huangbeyond(校园人渣)回复于 2003-09-03 13:36:11 得分 0

to:r3000()    
  如果"EXE不断监视此记载",的确是非常消耗系统资源的啊........  
   
   
  非常感谢上面几位的帮助,我现在在加紧时间测试,一旦完成,立即结贴  
   
   
   
  还有别的朋友有更好的,或者其它的方法吗?Top

7 楼jnxulei(石头)回复于 2003-09-03 15:46:39 得分 0

对表的所有操作在日志中有记载,你仔细研究一下日志文件Top

8 楼jnxulei(石头)回复于 2003-09-03 15:48:03 得分 0

对表的所有操作在日志中有记载,但俺没有研究过日志文件Top

9 楼huangbeyond(校园人渣)回复于 2003-09-03 22:50:39 得分 0

继续推......Top

10 楼small_wei(small)回复于 2003-09-04 01:28:33 得分 0

日志文件用户应该是用不上的Top

11 楼r3000()回复于 2003-09-04 10:18:03 得分 0

"如果"EXE不断监视此记载",的确是非常消耗系统资源的啊........"  
   
  消耗的仅是客户端资源,对于server端,不过是一个查询用户,比触发器要节约的多。  
   
  我只是建议一个思路,印象中,见过类似的东西,没有用触发器和DLL.  
   
  Top

12 楼huangbeyond(校园人渣)回复于 2003-09-04 12:00:25 得分 0

TO:small_wei(small)    
   
  我遇上一个难题:我的EXE和SQL服务器并不在一台计算机上,如果使用触发器-DLL的话,那么,就要涉及“机器间进程通讯的问题”。这样一来,触发器-DLL就要使用“WINSOCK等系统通讯技术”来进行更新通知。这样会导致各个程序之间复杂度大大加剧。  
   
  还有什么别的好办法吗?Top

13 楼zhaolaoxin()回复于 2003-09-04 12:26:20 得分 0

没有其他方法,只能用数据库自身的触发器功能来执行一个程序,所有要做的其它工作由这个程序完成。Top

14 楼ZHENG017()回复于 2003-09-04 13:32:11 得分 50

就使用dcom呗。新建一个trigger,在trigger像下边这样调用:(从msdn中copy出来的)  
  关键是使用"sp_OACreate",在msdn中index   "sp_OACreate"  
  DECLARE   @object   int  
  DECLARE   @hr   int  
  DECLARE   @src   varchar(255),   @desc   varchar(255)  
  EXEC   @hr   =   sp_OACreate   'SQLDMO.SQLServer',   @object   OUT  
  IF   @hr   <>   0  
  BEGIN  
        EXEC   sp_OAGetErrorInfo   @object,   @src   OUT,   @desc   OUT    
        SELECT   hr=convert(varbinary(4),@hr),   Source=@src,   Description=@desc  
          RETURN  
  END  
  Top

15 楼21bird(世纪笨鸟:csdn的blog啊啥时能不出错?!)回复于 2003-09-13 15:17:00 得分 0

用odbc的.exe啊?  
  那好像就没戏了,不过我刚查到oledb倒是提供了实现此功能的接口。  
   
  书上说oledb服务器在rowset发生改变的时候,会发送通告。  
  要接收这些通告,客户必须实现IRowsetNotify接口,并将其注册到服务器去。  
   
  应该可以用atl   oledb实现。具体请查阅相关文档。  
   
  想知道asp程序做的改变?asp一般都是用ado的,其实ado调用的就是oledb~~~~  
  所以我想他一定会发送那种通告……Top

16 楼mahatma_cn(研究硕士生)回复于 2003-09-13 23:53:18 得分 0

ado啊,满足你的要求Top

17 楼chen_pin(小品)回复于 2003-09-14 11:19:29 得分 0

UP_ItTop

相关问题

  • 有没有Delphi使用SQL数据库,修改查询SQL数据库内容的程序代码?我是初学者.
  • 有没有Delphi使用SQL数据库,修改查询SQL数据库内容的程序代码?我是初学者.
  • 修改多条sql数据库记录
  • 在程序中恢复sql数据库,如何解决用户占用sql数据库的问题?
  • 如何修改SQL数据库表中的数据
  • 不能修改SQL数据库表纪录怎么回事?
  • 怎样修改SQL数据库的登陆密码?
  • 如何用SQL语句修改SQL数据库的结构
  • 如何在VB中实现修改SQL数据库中的值?
  • VC程序访问SQL数据库的问题

关键词

  • .net
  • s60
  • sql-server
  • sql数据库
  • 存储过程
  • 函数
  • 数据
  • 修改
  • 编译
  • 连接

得分解答快速导航

  • 帖主:huangbeyond
  • small_wei
  • njtlxm
  • r3000
  • ZHENG017

相关链接

  • Visual C++类图书
  • Visual C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo