在大家的印象中,我是不是很.........不说了,对技术我还是蛮较真的在数据库的开发中,这是一个古老的话题,不管大家用的是二层,还是多层,都会碰到数据库刷新的问题,特别是在实时性要求非常强的系统中,如果保证每个运行的客户端都是最新的数据,打个比方,我现在有几条生产线,A、B、C生产线同时运作,各自运行独立的程序,A产生一条记录,要求B能够立即看到,B产生的一条记录要求C立刻看到,实现的方法有很多种,各种方法也有利有弊,不知各位在现实中是如何处理或者有什么好的方案与建议,大家探讨一下,互相学习借鉴,共同进步
解决方案 »
- 怎么把子from在主from的panel里显示啊
- TXmlDocument控件使用问题
- 为什么我这样写ADO创建过程不行呢?
- 用table控件gotokey方法,这样写对不对?
- 初次编写WEB服务器遇到难题,请高手指点。
- 高手帮忙
- 我有两个表table1,table2,关系通过id栏连接,现用dbgrid1显示table1的所有内容,当我在dbgrid1中点击某个记录时,要求在dbgrid2中显示相
- 各位高手,请出手 关于adoquery的sql问题
- 转载:一个程序员的忏悔录(巨长,慢慢看)
- 四个简单的小问题
- 关于数组类型和参数的问题!急
- adoquery调用insert语句错误的问题,在线急等!
你还把我叫出来,真不通人情
用消息或者SOCKET都能实现吧
具体差别不好说,没有什么项目经验
不过我以前做过扑克牌的网络游戏,
有一家的排变了,其他的玩家显示的桌面都变了
应该差不多吧?
当时就是用的SOCKET发广播猛鸟说的那个我也没用过,听听课
我以前的解决方案也是通过发消息,定义一个结构来表示要更新信息
type
TDBUpdateMsg = record
PrimaryInfo: PChar; //主键信息
Operate: TDBOperate; //操作类型,表示新增,删除,更新等
end;如果是新增或更新就跟所主键信息在数据库中找出来,添加或更新
删除就更方便了,不多说了,
其实大家关心主要是效率问题,同步问题在次要
希望大家踊跃参与,
猛兄说的那个Event我还蛮感兴趣,望不吝赐教
这个问题在多层结构中是一个很难处理的问题,因为应用服务可能有多个,当需要更新时需要通知多个应用服务,再由去通知客户端。由服务去通知客户端并不难,但服务如何立即知道数据已更新一个。当一个应用服务更新数据时,由它负责通知其它有应用服务并不现实,并且更新也许是由其它服务(或程序)引发的。也许有些数据库的触发器以通知外部连接……
我觉得这个问题目前恐怕没有一个可移植的方案,操作不同的DBMS时要使用不同的方案。我作过的项目中都没有这样的要求,反而在对操作不同DBMS方面很高,所以也没有接触过这一方面。不过我觉得既然数据是到数据库的,那么对于数据更新显示的实时性要求一般不会很高,对于这类信息用客户定时申请,服务端用时间戳进行检验的方法也应该可以满足,这样可以不破坏“被动服务端”的模式。
另外就是老掉牙的,定时刷新,土是土了点,但简单、实用、一直有效。
其实当应用服务知道更新后如何通知客户端已经不是问题,可以主动通知(这就要求用非阻塞方式连接或客户端开启回调端口——如果用TCP协议连接的话),也可以等待客户端查询,作一个规规矩矩的“被动服务端”。这两种方法是可以的。
关键就是如何让应用服务知道更新的发生。为了达到最大的通用性,不能使用与DBMS密切相关的技巧,一种方法是应用服务进行监视,只适用于需要监视的数据较少时;另一种方法是再运行一个“应用服务管理器”,所有已启动的应用服务都登记到这个管理器,当某个应用服务引发了数据更新,就通知应用服务管理器,再由它负责通知各个正在运行的应用服务。应用服务以在很多机器上有很多,但管理器应该只有一个。
视多种情况而定了,我用过几次方法..最笨的当然是轮循,有时候,这仍然不失一种解决办法.
主要是应用程序完全围绕数据库为中心情况下(二层结构).
在二层结构中,也试过几种办法,如SQL SERVER2000可以调用外部的组件,
不过这样来通知客户端,主意应该还是有点馊.在三层结构,数据模型在中间层可以体现,这时候可以充分应用各种技巧..
当一个客户端更新数据后,由中间层可以来通知其它客户端,
自定义消息(单机)和COM连接点接口方式,我还是比较喜欢消息方式的.另外,做一个自定义SOCKET方式连接的客户端时候,因为客户端是DOS环境,
实现多任务事件有点得不偿失,就还是用主动轮循作链路维护兼状态检查.另外,COM+事件服务有点意思..
采用另外一套机制,消息,或者TCP通讯
当客户端提交数据后,就给服务器一个信号
服务器受到信号
在转发给其他客户端
所有的客户端收到服务器发来的信号,全部刷新这样有个好处,可以和数据库得同步分开,
如果多个客户端同时提交,只要处理好数据库得同步问题就行了
客户端按照信号的顺序不断刷新就行了
但是缺点也显而易见
客户端会做很多无用的刷新
但是只有最后一次刷新才是我们想要的
使用三层结构:Client-AppServer<->DataBase Server
做一个像QQ群组那样的效果
坏处是AppServer和Client要使用一套标准传输,麻烦而且服务用户数是很有限的
好处是可同时响应,AppServer和Client中可以使用SSL等加密保护,可靠性就很高了只是个想法,实现起来可不是容易的事情
即 Atomic原子性, Consistent一致性, Isolated隔离性, Durable永久性原子性
就是事务应作为一个工作单元,事务处理完成,所有的工作要么都在数据库中保存下来,要么完全
回滚,全部不保留
一致性
事务完成或者撤销后,都应该处于一致的状态隔离性多个事务同时进行,它们之间应该互不干扰.应该防止一个事务处理其他事务也要修改的数据时,
不合理的存取和不完整的读取数据
永久性
事务提交以后,所做的工作就被永久的保存下来
二 事务并发处理会产生的问题 丢失更新当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题、
每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。脏读
当第二个事务选择其它事务正在更新的行时,会发生未确认的相关性问题。
第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。不可重复读当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。
不一致的分析与未确认的相关性类似,因为其它事务也是正在更改第二个事务正在读取的数据。
然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。幻像读当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。
事务第一次读的行范围显示出其中一行已不复存在于第二次读或后续读中,因为该行已被其它事务删除。同样,由于其它事务的插入操作,事务的第二次或后续读显示有一行已不存在于原始读中。
三 事务处理类型自动处理事务系统默认每个T-SQL命令都是事务处理 由系统自动开始并提交
隐式事务当有大量的DDL 和DML命令执行时会自动开始,并一直保持到用户明确提交为止,切换隐式事务可以用SET IMPLICIT_TRANSACTIONS
为连接设置隐性事务模式.当设置为 ON 时,SET IMPLICIT_TRANSACTIONS 将连接设置为隐性事务模式。当设置为 OFF 时,则使连接返回到自动提交事务模式
用户定义事务由用户来控制事务的开始和结束 命令有: begin tran commit tran rollback tran 命令
分布式事务
跨越多个服务器的事务称为分布式事务,sql server 可以由DTc microsoft distributed transaction coordinator
来支持处理分布式事务,可以使用 BEgin distributed transaction 命令启动一个分布式事务处理
四 事务处理的隔离级别使用SET TRANSACTION ISOLATION LEVEL来控制由连接发出的所有语句的默认事务锁定行为从低到高依次是
READ UNCOMMITTED执行脏读或 0 级隔离锁定,这表示不发出共享锁,也不接受排它锁。当设置该选项时,可以对数据执行未提交读或脏读;在事务结束前可以更改数据内的数值,行也可以出现在数据集中或从数据集消失。该选项的作用与在事务内所有语句中的所有表上设置 NOLOCK 相同。这是四个隔离级别中限制最小的级别。举例设table1(A,B,C)
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3新建两个连接
在第一个连接中执行以下语句
select * from table1
begin tran
update table1 set c='c'
select * from table1
waitfor delay '00:00:10' --等待10秒
rollback tran
select * from table1在第二个连接中执行以下语句
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
print '脏读'
select * from table1
if @@rowcount>0
begin
waitfor delay '00:00:10'
print '不重复读'
select * from table1
end第二个连接的结果脏读
A B C
a1 b1 c
a2 b2 c
a3 b3 c'不重复读'
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
READ COMMITTED指定在读取数据时控制共享锁以避免脏读,但数据可在事务结束前更改,从而产生不可重复读取或幻像数据。该选项是 SQL Server 的默认值。
在第一个连接中执行以下语句
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
begin tran
print '初始'
select * from table1
waitfor delay '00:00:10' --等待10秒
print '不重复读'
select * from table1
rollback tran
在第二个连接中执行以下语句
SET TRANSACTION ISOLATION LEVEL READ COMMITTEDupdate table1 set c='c'第一个连接的结果初始
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3幻像读
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
a4 b4 c4
SERIALIZABLE在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。这是四个隔离级别中限制最大的级别。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同。
在第一个连接中执行以下语句
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
begin tran
print '初始'
select * from table1
waitfor delay '00:00:10' --等待10秒
print '没有变化'
select * from table1
rollback tran
在第二个连接中执行以下语句
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
insert table1 select 'a4','b4','c4'
第一个连接的结果初始
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3没有变化
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
五 事务处理嵌套的语法和对@@TRANCOUNT的影响BEGIN TRAN @@TRANCOUNT+1
COMMIT TRAN @@TRANCOUNT-1
ROLLBACK TRAN 使@@TRANCOUNT回归0
SAVE TRAN 不影响@@TRANCOUNT举例
1)SELECT '事务处理前', @@TRANCOUNT --值为 0
BEGIN TRAN
SELECT '第一个事务', @@TRANCOUNT --值为 1
SELECT * FROM table1
BEGIN TRAN
SELECT '第二个事务', @@TRANCOUNT --值为 2
DELETE table1
COMMIT TRAN
SELECT '递交第二个事务', @@TRANCOUNT --值为 1
ROLLBACK TRAN
SELECT '回滚第一个事务', @@TRANCOUNT --值为 0
2)
SELECT '事务处理前', @@TRANCOUNT --值为 0
BEGIN TRAN
SELECT '第一个事务', @@TRANCOUNT --值为 1
SELECT * FROM table1
SAVE TRAN t1
SELECT '保存第一个事务后', @@TRANCOUNT --值为 1
BEGIN TRAN
SELECT '第二个事务', @@TRANCOUNT --值为 2
DELETE table1
ROLLBACK TRAN t1
SELECT '回滚到保存点t1', @@TRANCOUNT --注意这里的值为 2
IF @@TRANCOUNT>0
ROLLBACK TRAN
SELECT '处理结束', @@TRANCOUNT --为 0
SET XACT_ABORT
控制语句产生运行时错误时,是否自动回滚当前事务比如SET XACT_ABORT ON
BEGIN TRAN
SELECT * FROM 一个不存在的表
ROLL BACKTRAN
PRINT '处理完毕' --执行结果没有到这一步
go
SELECT @@TRANCOUNT --值为1 产生孤立事务
六 事务调试语句
DBCC OPENTRAN如果在指定数据库内存在最旧的活动事务和最旧的分布和非分布式复制事务,则显示与之相关的信息
示例
下例获得当前数据库和 pubs 数据库的事务信息。-- Display transaction information only for the current database.
DBCC OPENTRAN
GO
-- Display transaction information for the pubs database.
DBCC OPENTRAN('pubs')
GO
补充:有关孤立事务请参见全接触SQL异常与孤立事务
一、首先从SQLServer中Error讲起,SQL中错误处理有些怪辟 错误级别同是16但结果都不同。 select * from 一个不在的表
if @@error<>0
print '这个没有输出'
go raiserror('',16,3)
if @@error<>0
print '这个输出了'
go exec('select * from 一个不在的表')
if @@error<>0
print '这个输出了'
go exec sp_executesql N'select * from 一个不在的表'
if @@error<>0
print '这个输出了'这样你可以发现通过exec或sp_executesql执行可疑的sql,这样就可以在后面捕捉到被异常终止的错误。
二、引出孤立事务:
1、孤立事务的产生 select @@trancount 当前连接的活动事务数 --当前连接的活动事务数为0 begin tran select * from 一个不在的表
if @@error<>0
begin
print '没有执行到这里来!'
if @@trancount<>0 rollback tran
end commit tran select @@trancount 当前连接的活动事务数 --执行后你看看 当前连接的活动事务数为1,且重复执行会每次累加,这是很耗资源的。 应为rollback根本就没有被回滚。 2、使用现有手段解决孤立事务
print @@trancount print '当前连接的活动事务数' --当前连接的活动事务数为0 if @@trancount<>0 rollback tran --在这里写可以让孤立事务只保持到下次你的过程被调用
begin tran select * from 一个不在的表
if @@error<>0
begin
print '没有执行到这里来!'
if @@trancount<>0 rollback tran
end commit tran ---执行后你看看 当前连接的活动事务数为1,但重复执行不会累加
print @@trancount print '当前连接的活动事务数'三、使用 set xact_abort 来控制部分违反约束的错误的执行过程 create table Table1 (a int check(a>100))
go set xact_abort on
begin tran
insert table1 values(10)
print '这里没有被执行'
commit tran
go
print '' print '==============================================' print ''
set xact_abort off
begin tran
insert table1 values(10)
print '这里被执行'
commit tran go
drop table table1但 set xact_abort 对于编译产生的错误确没有起作用,且同样会产生孤立事务 set xact_abort on
begin tran
insert 一个不在的表 values(10)
print '这里没有被执行'
commit tran
go print '' print '==============================================' print '' set xact_abort off
begin tran
insert 一个不在的表 values(10)
print '这里没有被执行'
commit tran
go select @@trancount 当前连接的活动事务数 ---有两个孤立事务
if @@trancount<>0 rollback tran
对于sql中怪辟的各种错误,和孤立事务在t-sql编程中一定要注意,小心孤立事务的陷阱,尽量避免浪费或孤立资源,Microsoft公开宣布过SQLServe下一版本Yukon将有内置异常处理语法。那时可以通过代码对无法预料的错误有更好的控制。
我用的是 SocketConnection,曾考虑使用它的回调功能,但这就要对客户端的配置有要求了,所以放弃了。现在我的做法与你类似,添加 Socket 组件,用 Socket 来通知客户端数据已经更新了。
我觉得应该用推方法。也就是服务端向各个客户发消息表示有更新数据。我觉得最好用的还要算是用Udp,不但局域内而且公网上用代理也很容易实现。如果用sock在局域内好实现,但在公网上用代理时就不好实现了。
我也认为定时刷新是最简单最有效的方法,这里定时刷新也是一个相对的概念,它相当于定时+系统空闲,但通过先Close,再Open显然是不明智的,你能保证客户只需要在客户端显示一条记录吗,客户要求显示几百几千甚至几万条是很普通的,就拿我这个系统来说,他需要看到每条生产线上录入的的有数据,以便进行监控,而不是你一厢情愿说为了系统的效率怎么样怎么样,客户才不管你那么多。
所有归要结底,是如何在客户端定时刷新能够得到最实时的数据,又不用消耗系统太大的资源
个人觉的,楼上的短风和阿德所言有很高的参考价值;以下说一说个人的观点:
如果是两层的话,情况可能稍微好一些,因为我们的Servaer only one ,所以,在这种情况下,可以将重点放在数据库服务器上,利用数据库本身体的一些特性,如触发器等来通知客户端进行信息更新,或者是以客户端的访问为代价来解决这个问题,而且,在两层中,这种单通讯的方式对实时性的破坏并不是很大;我们甚至可以在用户的连接上下文章,或是在客户端的数据提取上进行,比如我们可以限制用户的数据提取;而进行每次实时的连接,当然,如果对于Web方面,这种方法可能不是很好用,但是在Web方面,短信息的方式是一个很好的选择;
而在三层中或是多层中,我的建议是不要和具体的数据库进行相关,当然,我们可以做成触发器,但是有一点要想到的是,在多层中,我们的数据库服务器很大的情况下并非only one,此时问题就会出来,我们用的也可能是多个Application Server,但是多个Application Server之间是必然有联系的,但是多个数据库服务器之间的联系却相当的微妙,其中一个数据库服务器的改变可能对于另一个数据库服器的改变是未知的,于是于数据库服务器绑定的刷新、回访机制就必须做许多额外的工作,甚至于还是吃力不讨好的;所以,我觉的我们应该把更多的精力放在Application Server上,因为Application Server本身就是各种规则的封装,虽然,可以多个Application Server,但是回头想一想,为了让整个应用程序达到均衡负载,那么,这些Application Server本身就存在着联系,而且在多层中还有一个特殊的情况就是可以实时的跟踪每个客户端的CDS的数据的更新状态,数据笔数等信息;而当Client 进行CDS更新的时候,那么它的第一步就是通过Application Server进行反映出来,也就是说数据库服务器的更新情况对于Applicaton Server而言是没有一点透明性的,Application Server可以实时的得到数据库服务器的更新,本身而言,为了达到数据的同步性,此时Applciation Server一定要做其它的工作,即使用数据服务器间的更新机制来做到数据的同步,但是不同进程中的Application Server依然可以明确的知道数据库服务器的更新状态,而无论以什么样的方式,客户端想得到数据库服务器的最新数据,肯定要通过Application Server(应用程序服务器或是中间件)来得到,而进行数据回传,也只有能过Application Server进行完成;我们可以用Application Server 的回调进制实现,至于到底采用什么样的回调方式来实现,此时已经与本问题无关了,我们可以用DCOM,也可以仅仅用winSocket;_____________________________________________________________________暮春三月,羊欢草长,天寒地冻,问谁饲狼?人心怜羊,狼心独怆,天心难测,世情如
霜……
言有尽而意无穷,余意尽在不意中
另一方面,定时刷新只会增加Applicaton Server ,DB Server 的工作压力!
而实质性的问题并不一定能解决,因为在多个DB Server的情况下,你如何能保证每一个Client的刷新可以动态的,在最恬当的时间内得到最新的数据?本来,多DB Server的情况下,一个DB Server进行更新的同时,就需要保证other DB Server的同步;为什么我们不可以继续下去,在利用这个同步的特性来进行回调呢?而此时再用刷 新的话,无疑就是我们抛弃了一个已经给我创建好的机会不用,而自己用了另一种吃力不讨好的方法来完成;
_____________________________________________________________________暮春三月,羊欢草长,天寒地冻,问谁饲狼?人心怜羊,狼心独怆,天心难测,世情如
霜……
言有尽而意无穷,余意尽在不意中
第二加入ServerSocket(Server端),ClientSocket(Client端),当服务端AfterUpdateData中写入:for i:=0 to Client_Number-1 dobeginServerSocket.Socket.Connections[i].SendText('Client Refresh');end;在Client端中的ClientSocket的OnRead事件中:var str:string;beginstr:=Socket.ReceiveText;if str='Client Refresh' thenbeginClientDataSet.Close;ClientDataSet.CommandText:='select * from table';ClientDataSet.Open;
end;
end;
这种方法 不错 我一直在用:)
方法一:客户端定时刷新;
方法二:服务端用SOCKET通知。
通过应用服务器来更新客户端的局限性很明显,往往受束于一种特定技术或环境,并且这种方法对于数据的能否正确地传递到服务器端也是一个问题,就算不用存储过程,通过SQL语句更改数据非常普遍,这几乎是不可避免的,另外各种复杂的主从表更新应用服务器如何传递这些数据也是较为棘手的
就算用一个代理服务器来实现这个功能,代理服务器出现故障怎么办,所以我现在一直很踌躇我现在考虑用客户端实时刷新的方法,这里的实时=定时+系统空闲,确实是一种简单而有效的方法,
技术的难度就在于如何只抓取最新的数据,而不是一股脑的Close,Open。因为你无法预料用户需要显示多少数据,用户需要显示几百几千条甚至几万条数据都是可能的,就拿我们现在这个系统来说吧,十几个生产线同时动作,一个生产线几十个工位, 用户的需求就是要能看到每一台机器录入的数据,为了效率应该只返回少量数据那是你一厢情愿,用户才不管你那么多。技术的难度现在就归结到这里了,如何抓取客户端不存在的数据!
TimeStamp
你指的是三层的情况?这只要用点手段就好了嘛,比如把TIMESTAMP字段从更新字段中去除(即不更新此字段)即可
Application Server就是数据规则的处理,正如我们C/S的Client,用户的数据操作能不经过Application Server吗?肯定要经过,无论成功也罢、失败也罢,肯定要经过应用程序服务器的,那么总的来说,应用程序服务器是一个完全可以感知到数据的操作(实时的变动,成功、失败、浏览等),而我的确想不出用UDP,简单的Socket有什么好处?我们列举一个简单的例子:AS (Application Server) 3
C (Client) 100
DS (DataBase Server) 2这样的一个系统不算大吧,可能唯一不合适的就是AS和DS的分离,或者是说没有必要搞那么多的AS、DS,不管如何,我们现按照这样的假定来模范一下;3个AS可以承认100C,这不在话下,但是,是否应该考虑到各种Pooler的情况?如果以UDP发?重新建立一个连接?不分析了,偶去写方案去了_____________________________________________________________________暮春三月,羊欢草长,天寒地冻,问谁饲狼?人心怜羊,狼心独怆,天心难测,世情如
霜……{言有尽而意无穷,余意尽在不言中……}
我做過的一個項目, 有這樣的問題, 你又有何高見呢??
在我的實際項目中, 是多用戶環境, 用戶可用我的client程序, 產生相關的update或其它SQL語句, 提交到我的Server程序,然後, 提交給MsSQL, 這樣, 控制多用戶刷新到最後數據也還可以控制!但現在, 用戶可能也可用第三方程序, 甚至于類似"Query Analyzer"類的程序不通過我的server程序來更新數據庫, 那這樣, server端程序就無法控制相關的client的更新! 現在只能用個定時器來輪徇檢查, 很沒有效率!
在java里就是用JMS
在微软的方案例里就是com+松耦合事件,学学吧!会迎刃而解;
这才是正路
你指的是三层的情况?这只要用点手段就好了嘛,比如把TIMESTAMP字段从更新字段中去除(即不更新此字段)即可
------------------------------------------------------
你指的是ProviderFlag中的pfInUpdate吗,不知道你理解了它的意思没有,它只表示客户对这个字段的更改有效没效,我客户端改它?
解决方案,三层中可以通过设置UpdateMode为upWhereKeyOnly,而二层中就很麻烦to ihihonline(小小) :头到晕了,不知道楼主是否好好的分析过三层?
Application Server就是数据规则的处理,正如我们C/S的Client,用户的数据操作能不经过Application Server吗?肯定要经过,无论成功也罢、失败也罢,肯定要经过应用程序服务器的,那么总的来说,应用程序服务器是一个完全可以感知到数据的操作(实时的变动,成功、失败、浏览等),而我的确想不出用UDP,简单的Socket有什么好处?我们列举一个简单的例子
----------------------------------------------------
请问我在应用服务器上通过存储过程加入几条记录,应用服务器能感知?
一个应用服务器的操作另外一个应用服务器能感知?
其实难点只是在如何让应用服务知道更新这一问题上。如果所有更新都是由应用服务来完成的,这时就可以用我说过的应用服务管理器来负责更新通知,不过要求所有的应用服务都很规矩。
如果还允许客户端直接用数据库工具修改数据(???好象失去了三层结构的安全性优点)或是还允许其它组织(或个人?)开发的应用服务修改数据,如果还要通用的话,可能只能使用主动查询的方式了——通用与性能总是很难融洽相处的。另一个选择就是放弃通用性,用DBMS相关的方式来完成。
其时可以把上面两种方法结合起来,由一个应用服务管理器来负责通知你的应用服务,而管理器获知这一消息的方法使用不同的DBMS的能力来实现,甚至一个服务管理器可以同时有多种方式,根据DBMS的不同而使用不同的DBMS相关对象,而用查询的方式来检测不支持这一能力的DBMS或是未知类型的DBMS的更新操作。 关于从应用服务到客户端的通知,无论是服务端回调还是客户端查询的方式都有道理,前面已经有人说过了,这其实就是一个观察者模式的实现问题。具体协议可以参考DDE的实现。不过当用COM+时通常会考虑服务端通知的方法,因为太容易了。而如果是直接用TCP协议传输并且选择了阻塞方式则一般会由客户端查询;或者在每一次对客户端的任何请求的响应时把最近的更新信息附加上去,这时就要求客户端的代理对象要识别这一附加信息并触发事件。