大家都是关税
***************
介绍MTS的Object Pooling技术
徐 明
MTS对Object和Transaction的巧妙管理,让3-tier系统的弹性(flexibility)、拓展性(scalablity)和执行效率(performance)得以尽情发挥出来。如果您能充分了解MTS的Object Pooling技术,则您开发的企业元件(business component),将能在MTS的执行环境(run-time environment)里如鱼得水,并能够顺畅地执行企业流程(business process)的各种交易(transaction)活动。
前言
现在的企业主管与软体分析师们都以企业流程(business process)为核心,并为企业流程建立Use Case模式。企业流程包含一连串的商业交易(transaction)活动,Use Case模式就表达这一连串交易。所以Jacobson[1]说:
“A use case is a sequence of transactions in a system whose task is to yield a result of measurable value to an individual actor of the system.” [一个use case 表达系统里的一连串交易,这一连串交易的任务是要为此系统的个别使用者提供一项可评量价值的服务。]
Use Case模式里的这些交易活动将分派给各企业元件(business component)分工合作去执行。
MTS(Microsoft Transaction Server)管理这些企业物件,协调资料库等软硬体资源,协助这些企业元件,使它们能够流畅快速处理Use Case里的交易。所以人们常称MTS为Object Transaction Server。除了MTS之外,其它公司也有,例如Sybase公司的CTS(Component Transaction Server)也是。
例如根据MTS Hot News[2]的消息,在1997年间,通用汽车公司利用MTS与VB开发贷款服务系统;SunAmerica财务服务公司,利用MTS与VB,开发WWW式的退休金存款系统;Ryder交通服务公司,开发VB + MTS的车辆维修系统,获得极佳的成效。
此外,微软公司与一些厂商公开测试NT + MTS + SQL Server的三层架构系统,实际运作在每天十亿笔交易的环境下,显示MTS的功能与稳定度。
MTS元件之特性
欲了解MTS元件的特性,可从它所处的多人使用(multi-user)环境谈起,看看MTS元件必须具备那些性质,才能支持Transaction处理,达到数千人共同使用的境界。
在电脑方面,交易(Transaction)原是资料库领域的一个重要的观念和技术。这种资料库交易(database transaction)就是处理资料库的查询、更改等动作,并考量同时性(concurrency)的需要;换句话说,就是资料库在多人使用(multi-user)的环境下,如何确保同时读取或写入资料时,资料库仍能正常运作。
在三层式主从架构系统中,常有许多个座落在不同地点的资料库,对这些资料库的交易处理常由中间层的元件负责。通常一笔企业交易(business transaction)会含括许多项的资料库交易,例如一笔买卖至少有借、贷两项记录(entry),必须进行两项资料库的更新动作,形成两个资料库交易。再如银行的转帐商业交易,必须从一个帐户提领金额,将它存入另一个帐户里,也含括两项资料库交易。
负责商业交易的元件必须委托数个其它元件负责各个资料库交易。换句话说,就是由许多个元件共同协力完成一个商业交易。我们称这种元件为「交易元件」(transactional component or object)。而担任管理这些元件去执行交易(perform transaction)、确定交易(commit transaction)、及回复交易(roll-back transaction)等工作的就称为Object Transaction Server。
典型的三层式架构如下:
图1、MTS主控component-tier
在多人使用环境下,当Client物件想要委托Server元件存取资料时,此时元件的合作方式有二:
1. 假如在Client程式的萤幕画面上,按下「提款」按钮,则会发出一道讯息给中间层的Server元件。此时会先建立Server元件,然后才呼叫Server元件的函数,待Server执行其该函数并送回资料后,就马上删除该Server元件。此情况的Server元件寿命等于Client程式的一道讯息执行时间。
2. 当Client程式开始启动(或诞生)时,就建立Server元件,Client程式可呼叫Server元件的一些函数,直到Client程式结束时,才删除Server元件。此情况的Server元件寿命等于Client程式的生命周期。
其中,第1种方式,看起来Client程式的每道讯息的执行时均有类似「启动/关闭」之类的动作,有点浪费执行效率。
但对于Server元件而言,每道从Client程式传来的讯息(请求执行Server元件的函数),彼此之间没有相关,而是互相独立的任务。因之可把「启动Server元件」当成是「设定锁定旗标」(lock flag),然后把「关闭Server元件」当成是「取消锁定旗标」,代表此Server元件已完成Client程式所交代的任务了,Server元件就可以转台为别的Client程式服务了。那么Server元件的「同步控制(concurrency control)」工作,顿时轻松不少!
就交易(transaction)观点而言,在第1种解决方案下,交易的开始,便是每道讯息初的「建立Server物件」;交易的结束,则是每道讯息末的「删除物件」,故交易的范围便是一道讯息的始末。由于每项交易皆具有ACID特性,其中的I(即Isolation)表示我们可各项交易看成互相独立。所以上述的第1种方法恰好合乎交易的特性,而且能让 Server元件迅速转台于众多的Client程式之间,有利于多人使用的环境。
至于,在第2种方法下,交易的范围则是整个Client程式的生命周期,在这么长时间里,Server元件被锁定,无法迅速转台,不利于多人使用的环境。由于Server元件无法将Client程式送来的讯息视为独立不相关,此时Server物件便必须考虑:同时来自Client程式的两个以上讯息,该如何将之序列化(serialize),使得不致发生同时写入,或是一个写、一个读的情况,以便能永远维持资料库里资料的一致性。这种方式,让Server元件的程式变得很复杂。
由于MTS支持上述的第1种方式,所以MTS物件的程式撰写简单多了,而且交易较短,能支持更多人同时使用,提升系统的扩展性(sacalablity)。因此Lievano[2]提到:
“Under MTS control, you configure components to run inside a large-scale enterprise-type scenario.” [在MTS的控制之下,元件将能在大型企业的环境里执行。]
他又说:
“The key is that you design and implement them as single-user components---- as if only a single user would ever use them at any one time.” [其关键是您在设计与实作时,可设想它们只是单人使用的元件罢了---- 就像任何时刻皆最多只有一人在使用它。]
他又接着说:
“MTS allows for this simple mindset because MTS already implements the bulk of the multiuser code and logic itself.” [MTS能让我们以如此单纯的心态来设计元件,是因为MTS本身已经写好一堆程式码可支持多人使用的情形。]
综合上述,可知道MTS物件(元件)负责交易处理时,会以Server物件的函数始末为交易的范围,配合MTS本身的机制,就能支持高达数千人的同时使用。例如Object Pool就是MTS里的极重要机制。
MTS的
基本解决方案
上述的第1个方式显然是较佳之设计,因为其能任意扩大Client端程式的执行数目,但不必修改Server元件的程式码。并且,交易能从Client程式开始,也能从Server端的企业元件(business component)开始。更重要地,从Server端的企业元件开始的交易,更逼真地表达商业流程(business process)里的商业交易。 试想:某个企业元件提供一个转帐交易服务,当Client程式送讯息「从帐户A转钱到帐户B」给企业元件,基于交易的不可分割性质(atomicity),Client程式希望「钱能够全部转到帐户B,若不能,就把钱完全留在帐户A」,其不希望有任何中间状态发生(就是钱只转一半)。这个企业元件便实际处理此转帐交易(如从甲银行调出A的帐户余额,确定足够后,再转到乙银行的B帐号)。如此,交易搭配三层式架构,将使交易的理念更易于实现。
但是,第1种方式也有些缺点,如下:
l Client程式在每道讯息的执行时,要先建立企业元件,讯息执行结束时,也要删除企业元件。这将造成企业元件常常被建立、删除,使得系统效能不佳。
l 因为企业元件常常被建立、删除,使得企业元件连接到资料库(或资料物件,道理一样)的网路连接(database connection),也常常被建立、删除。这将使系统整体效能也不佳。
MTS采用前面的第1种方式,再加上解决前段所说的两项缺点,才能让系统的反应时间合理,与执行结果正确。 MTS的主要机制是:
1. 物件(或元件)池 (Object pool)
使得WWW物件虽然常常建立企业元件,但MTS提供Object Pooling机制,使得只有第一次建立物件耗时较多,接下来的建立、删除耗时很少。
2. 连接池 (Connection pool)
使得企业元件虽然也常常开、关资料库连接,但MTS提供连接池,使得这些动作也是只有第一次开连接时耗时较多,接下来的耗时就很少。
此外,MTS也是提供一个既简单又有效率的线串模型,让MTS元件面对多连接也维持高效率。MTS则依赖NT作业系统的丛集(Cluster)技术达到覆载平衡(load balancing)。 例如,微软的网站,便是使用十几台DEC Alpha的工作站,一起跑NT与IIS,共同为众多网友服务。讯息伫列(message queuing),则提供比交易更高一层的系统服务,此技术确保Client程式的讯息「一定会被送达到」Server元件(含括资料库)去执行,但不一定能保证「何时执行」。对于一些不需要立即处理的交易,这种方式倒可以增进Server资源更有效安排,也能加速给Client的反应,让前端使用者更加满意。(请参考本期杂志的「MSMQ与MTS」一文)。关于这项服务,微软也推出另一名为Falcon的Server(或称为MSMQ),与MTS搭配一起满足高级企业资讯系统的需求。
MTS的Object Pooling机制
在DCOM环境里,Client程式透过Proxy物件转送讯息给中间层的MTS元件。在Object Pooling机制中,Client程式每次传出讯息时,MTS就诞生元件或是从池子中取出元件,然后连接到Client物件里的Proxy,为Client程式服务,如图4所示。
图4、MTS元件与其Proxy
一旦服务完毕,就切掉元件与其Proxy的连接(link),将元件丢回池中或删除掉。
Object Pooling机制就在服务完毕时,将元件丢入元件池(object pool)里。当有需要时就能迅速从池中找出元件来支持Client端的Proxy物件。因为省掉了元件的诞生/删除的时间花费,一个元件能迅速转台支持更多的Proxy,为更多的Client程式服务。
图5、MTS的物件池
因为中间层的电脑容量通常无法随着 Client程式个数而成比例增加,所以Object Pooling成为提升中间层效率的重要技术。
在这机制下,MTS元件会处于4种可能的状态(state):
l 诞生(instantiated)状态
应Client程式之需求,MTS诞生(create)企业元件,但尚未连结到Client程式(里的Proxy),此时元件处于这个状态。
l 启动(activated)状态
一旦将元件连结到Client程式(里的Proxy),元件就转而处于这个状态了。
l 休眠(deactivated)状态
一旦将元件做完Client程式所交代的任务(如交易处理),MTS切掉它跟Client程式(里的Proxy)的连接,元件就转而处于这个状态了,元件被丢入池中。
l 删除(deinstantiated)状态
当MTS决定删除掉元件(可能因愈时没人用),元件就转而处于这个状态了。
在这过程中,MTS会监视所有来自 Client端的各项讯息要求。为了达到此效果,所有MTS元件都必须先经由MTS Explorer注册才能使用。因为经过注册手续,MTS才能拦截所有送到MTS元件的讯息,又因MTS元件必定采用COM动态呼叫,故在COM的注册资料库中,MTS元件在注册前后,其资料是截然不同的。注册前,它是*.dll型的;注册后,变成*.exe型的,此外尚有许多资讯也被更改,均是为了让MTS拦截讯息用的。
现在看看图2的元件状态图(state diagram)吧!当Client第一次启动MTS元件时,MTS诞生元件,然后元件便进入启动(activated)状态,为Client程式服务。在元件函数的最后,可能呼叫环境物件(context object)的SetComplete/SetAbort,把元件带回休眠(deactivated)状态;也可能呼叫环境物件的EnableCommit/DiseableCommit,元件仍处于启动(activated)状态,等待Client的下一道讯息。此时,如果Client呼叫删除元件,会把元件带回休眠(deactivated)状态。
当元件在休眠状态,且长时间均不再有Client启动元件,才会把元件真正删除(由系统计时器触发的)。当元件在休眠状态时,Client端只要呼叫元件的任一函数,均会把元件带入启动状态。
因之,如果Client短时间内有再要求建立元件,而池中有所需的元件在休眠状态,就直接启动之。节省了诞生/删除的时间。跟这诞生/删除动作的时间花费相比较,启动/休眠动作的时间花费就少很多了。所以元件能迅速转台为众多Client服务。
图2、MTS元件的状态转移图
MTS的ObjectControl介面
MTS提供ObjectControl介面,让元件能透过该介面来使用Object Pooling的服务。MTS元件只要实作ObjectControl介面,就可以得到Object Pooling的服务。ObjectControl介面提供三项服务如下:
Activate
当Client要求使用一个MTS元件时,MTS从Pool叫醒MTS元件后,会执行此运算。如果这个MTS元件是刚诞生的,不是从Pool叫醒的,元件会先执行Class_Initialize运算,才执行Activate运算。
Deactivate
当元件服务完毕后,会执行此运算。执行完毕后,执行CanBePooled若传回True时,就丢回到Pool里,让别的Client使用。当元件被删除时,会先执行Deactivate运算,再执行Class_Terminate运算。
CanBePooled
MTS元件诞生时会先执行Class_Initialize运算,而后执行此运算,接着才执行Activate运算。 CanBePooled说明此元件是否可以放于Object Pool中,如果传回值是True,意谓着可以放置于Object Pool中,等待Client使用之。
Client来的讯息确实一开始被MTS拦截,MTS会秉持「先建立环境物件、再建立MTS元件;先删除MTS元件,再删除环境物件」的原则。
在建立元件时,如果MTS元件没有实作IObjectControl介面,则MTS单纯地呼叫元件的建构元(IClassFactory)诞生物件;如果有,则呼叫元件建构元及Activate运算;当然,如果是第2次以后的建立,且元件有实作IObjectControl(即池中有此MTS元件),则单纯地把叫醒池中的元件即可。
在呼叫函数时,MTS都先呼叫元件的Activate运算。在函数的最后,如果呼叫环境物件的SetComplete/SetAbort,则元件进入休眠状态;如果呼叫环境物件的DisableCommit,代表现在尚未做完交易工作,故等到下次呼叫SetComplete,才能确认交易。
在删除时,如果MTS元件没有实作IObjectControl介面,则单纯地真正除去元件即可。 如果有,而且CanBePooled传回True时,则MTS会把此元件回收,丢到池中,供别的Client使用。
Stateless元件观念
MTS提供Object Pooling的技术,让大量的Client可以共享有元件,提高资源的使用率。但是,当元件放入Object Pool后,可能会被别的Client拿去用,会破坏它原先保有的资料内容(state)。 这跟传统的物件会持续保有资料的观念不同。前者是stateless的观念,后者则是stateful的观念。
所谓stateless的元件保有资料的时间,仅维持于单一运算的执行时间,而非持续于元件的整个生命周期。有些人把stateless误会成:MTS元件是不能有属性(attribute)的。其实并非如此,stateless元件仍可含有状态值(state),只是仅限于单一函数执行而已。
MTS元件程式设计
我们来看一程式范例,设计一个名叫Compute的MTS元件:
撰写程式:
'Compute Class'
Private m_iA As Integer
Private m_iB As Integer
Public Function Read(iA As Integer, iB As Integer)
As String
Dim theObjectContext As ObjectContext
Set theObjectContext = GetObjectContext()
m_iA = iA
m_iB = iB
theObjectContext.SetComplete
Read = "A+B=?"
End Function
Public Function Add() As Integer
Dim theObjectContext As ObjectContext
Set theObjectContext = GetObjectContext()
Dim iResult As Integer
iResult=m_iA + m_iB
theObjectContext.SetComplete
Add = iResult
End Function
Private Sub ObjectControl_Activate()
m_iA = 0
m_iB = 0
End Sub
Private Function ObjectControl_CanBePooled()
As Boolean
ObjectControl_CanBePooled = True
End Function
Private Sub ObjectControl_Deactivate()
End Sub
将Compute类别放置于ActiveX DLL中,制成ActiveX DLL档案安装于MTS中,形成MTS元件。
设计一个Form1的画面,并撰写VB程式检验Compute元件:
撰写程式:
'Form1 Class'
Private theCompute As ComputeDLL.Compute
Private Sub Form_Load()
Set theCompute =
CreateObject("ComputeDLL.Compute")
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set theCompute = Nothing
End Sub
Private Sub ReadCB_Click()
Dim iA As Integer
Dim iB As Integer
iA = Text1.Text
iB = Text2.Text
Label3.Caption = theCompute.Read(iA, iB)
End Sub
Private Sub AddCB_Click()
Label3.Caption = theCompute.Add
End Sub
将Form1放置于Stadard EXE中,会参考Compute所属的ActiveX DLL档案。这个程式范例分为两个步骤:
1. 分别在两个画面上的Text盒中输入两个数值,而后按下Read按键。此时Form1 执行其Read函数里的指令:
Label3.Caption
= theCompute.Read(iA, iB)
Form1传送Read(iA, iB)给Compute元件,MTS截取这个讯息,从池中叫醒一个Compute元件,连接到Form1里的Proxy(代表Server端的Compute元件),由theCompute指向(或Reference到)该Proxy物件。然后先执行ControlObject_Activate函数,再经由Proxy去执行Compute的Read函数,读取A、B,将它们指定给m_iA和m_iB属性,再传回「A+B=?」字串。最后执行ControlObject_Deactivate函数,再把该Compute元件丢回池中。
2. 接着,在画面上按下Add按钮,此时Form1 执行其Add函数里的指令:
Label3.Caption
= theCompute.Add
Form1要求MTS从池中叫醒一个Compute元件(这个元件不一定跟刚才使用过的那个Compute元件同一份,可能是另一个instance,致用不到原来存在m_iA及m_iB值),执行ControlObject_Activate函数,将m_iA和m_iB两个变数值设定为0,再执行Compute的Add函数,传回「A+B」之值0。最后执行ControlObject_Deactivate函数,再把该Compute元件丢回Pool里。
使用Stateful元件
把元件设计成为stateless的益处是:让MTS能自主地迅速将元件丢回Pool里,快速转台去为别的Client程式服务。然而您也可以限制MTS暂时不要将元件丢回Pool。第1道讯息处理的一些结果能留到下一道讯息继续使用之。其理由是:MTS并未将元件丢回Pool,Client程式里的Proxy仍继续连接到同一份MTS元件,元件里的 State就能留下来了。
由于MTS元件的主要工作是去执行企业流程里(business process)的商业交易(business transaction), 有些元件负责监督商业交易的完成,而商业交易又常可细分为数个资料库交易(database transaction),各由更小的元件负责执行或监督。这就是Component Transaction 的概念。
也就是说,一个transaction(含商业交易与资料库交易)常可细分为好几个sub-transaction,每个sub-transaction是一个工作单位,当每个元件(component)各负责的sub-transaction都圆满完成时,整个transaction里的所有活动才能全数一起成交(commit),只要其中的任何元件无法圆满达成其负责的sub-transaction,则整个transaction就全部无法成交,也就是交易的执行失败(abort)了。一旦transaction失败,交易无法成交,系统当然必须回复(roll back)到执行transaction之前的状态。
Component Transaction意指数个元件的活动形成一交易范围(transaction context),一旦任一个元件的活动无法完成,将造成transaction的失败。由于每个参与的元件负责一个sub-transaction,一旦sub-transaction圆满达成了,MTS就可以将该元件丢入 Pool里,也不会留下它的state值。这是最常见的情形,也是MTS能发挥最高效率的情形。
不过有些情况下,您会希望元件能留下来继续工作,不要那么快被丢回Pool里。其中最主要的场合是:该元件的数个函数共同来完成一个sub-transaction的工作。则state必须持续保留下来,直到sub-transaction完成为止。例如一笔交易常含有数项借贷分录,必须保持State才能正确处理之。
在MTS元件所伴随的环境物件(context object)里具有两个旗标(flag),元件可藉它来向MTS告知是否元件已做完其transaction或sub-transaction了。也藉之表达是否让MTS自主地将元件丢入池中。(有关元件的环境物件,请参考本期杂志的「3-tier系统实作的雕龙小技」一文)。
MTS的环境物件皆会支持IObjectContext介面,其含有四个运算,来协助我们设定环境物件内的这两个旗标如下:
旗标
运算
do
ne
Consistent
DisableCommit
False
False
EnableCommit
False
True
SetAbort
True
False
SetComplete
True
True
表1、环境物件里的旗标
这四个运算分别说明如下:
DisableCommit
意指元件负责的sub-tranaction尚未完成,亦即这sub-transaction尚未达到一致的状态(关于交易的一致状态,请参考本期杂志的「问题集#1」)。要求MTS不要将此元件丢入Pool,以便保留这个元件的state,使它的state可以跨过函数运算,继续处理它的state,完成sub-transaction的工作。
例如程式:
Public Function Read(iA As Integer, iB As Integer)
As String
Dim theObjectContext As ObjectContext
Set theObjectContext = GetObjectContext()
m_iA = iA
m_iB = iB
theObjectContext.DisableCommit
Read = "A+B=?"
End Function
指令:theObjectContext.DisableCommit要求环境物件将其内的“Done”设定为 False,告诉MTS不要把元件丢入池中;也将其“Consistent”设定为 False,告诉MTS此sub-transaction尚未达到稳定一致的状态,必须再继续做完,整个transaction才能圆满成交(commit)。例如再执行到函数:
Public Function Add() As Integer
Dim theObjectContext As ObjectContext
Set theObjectContext = GetObjectContext()
Dim iResult As Integer
iResult=A+B
theObjectContext.SetComplete
Add = iResult
End Function
这theObjectContext.SetComplete指令就将其内的“Done”和“Consistent”设定为True,告诉MTS此sub-transaction已达到稳定一致的状态了。
反之,如果未再呼叫这个Add(),整个transaction会Abort掉。
请留意,MTS会在函数执行完毕时才去参考这两个旗标值,所以只要将theObjectContext.DisableCommit指令摆在 Read = "A+B=?"指令之前的任何位置均可。
EnableCommit
这是环境物件内两个旗标的预设值(default),意指元件可能尚未进行sub-transaction的工作,所以交易仍然停留在稳定一致状态,所以“Consistent”旗标值为True。至于“Done”旗标值预设为False,告诉MTS不要把元件丢入池中。此外,如果元件已经完成sub-transaction的工作,交易达到稳定一致状态了,所以“Consistent”旗标值当然应为True;但是如果您有其它缘故而想把元件的state留下来时,也可使用指令:theObjectContext.EnableCommit。
无论您使用EnableCommit或DisableCommit,皆能把state留下来,使它的state可以跨过函数的呼叫,继续处理它的state,直到元件呼叫SetComplete或是SetAbort,MTS才把元件丢入池中。
SetAbort
意指元件已经做了sub-transaction的有关工作,但侦测到有些错误状况,致sub-transaction无法达到圆满一致的状态,元件必须将“Consistent”旗标设定为False,告诉MTS整个 transaction必须Abort掉。
既然工作被迫停止,没必要保留元件的 state了,所以把“Done”旗标设定为True,让 MTS有机会把元件丢入池中。
SetComplete
意指元件已经完成了sub-transaction的有关工作,使的sub-transaction达到圆满一致的状态,元件就将“Consistent”旗标设定为True,告诉MTS:“我成功了”。
工作圆满达成了,也没必要保留元件的 state,所以把“Done”旗标设定为True,让 MTS有机会把元件丢入池中。
如果工作圆满达成了,但希望保留元件的state,就用EnableCommit。
这两个旗标在元件离开函数时,才会发生效用。所以,可以无限次地改变旗标设定,唯独有离开函数前的最后一次设定才会有效。再者,只有Done的旗标为True的情况,元件才会回到Pool。所以也只有SetComplete或SetAbort之后才会执行Deactivate运算。
结语
Use Case模式善于表达企业流程里的一序列交易。所以在系统的需求分析过程里,就必须以Use Case去表达使用者和企业经营者心中的交易,因为商业交易是一项契约行为,企业经营者会相当关心,交易的正确性和完整性是必备的。
进入到系统设计阶段,Use Case模式将对应(mapping)到物件模式,把各项商业交易或资料库交易分派给各元件,再由MTS来协调各元件,以及监视各元件进行交易处理的结果,确保交易的正确性和完整一致性。
到了程式实作阶段,必须熟练MTS的机制,例如Object Pooling、Transaction Commit/Roll-back等,就能创造出好用的企业元件,强力支援Inernet/Intranet上多如银河星星般的远端使用者。n
参考资料
[1] Jacobson, I., The Object Advantage, Addison Wesley, 1995, p. 105.
[2] Lievano, R. and Gray, S., “Build Enterprise Apps with MTS”, Visual Basic, Vol. 7(11), 1997.
[3]周瑞, OLE COM/ActiveX程式设计, 物泽, 1997.
[4]Microsoft Transaction Server Hot News, 1997.
[5]Microsoft Transaction Server Help, 1997.
[6]David Chappell, “Objects, Components, and Transactions”, Object Magazine, OCT 1997, pp.14-18.
关于MTS 的建议参考书籍
1. Roger Jennings, Microsoft Transaction Server 2.0, SAMS, 1997, ISBN 0-672-31130-5. (维科)
2. Roger Sessions, COM and DCOM: Microsoft‘s Vision for Distributed Objects, John-Wiley, 1998, ISBN 0-471-19381-x. (维科)
3. Wrox, Visual Basics 5.0 : Business Objects, Wrox, 1998. (碁峰)
4. Yen-Ping Shan and ralph Earle, Enterprise Computing with Objects, Addison Wesley, 1998, ISBN 0-201-32566-7.(维科)
※此外 Microsoft Transaction Server Online Help 是重要参考资料。
关于UML 的建议参考书籍
1. Craig Larman, Applying UML and Patterns: An Introduction to Object-oriented Analysis and Design, Prentice-Hall, 1998, ISBN 0-13-748880-7. (维科)
2. Eriksson, UML Toolkit, John-Wiley, 1998. (维科)
3. Pierre-Alain Muller, Instant UML, Wrox, 1998, ISBN 1-861000-87-1. (碁峰)
4. Martin Fowler, UML Distilled, Addison-Wesley, 1997.(松岗)
※此外 物件导向杂志 从第5期开始的UML系列文章,是重要参考资料。