當(dāng)前位置:工程項(xiàng)目OA系統(tǒng) > 泛普各地 > 河北O(jiān)A系統(tǒng) > 石家莊OA系統(tǒng) > 石家莊OA信息化
Web Service Case Study: 事務(wù)性Web服務(wù)
申請(qǐng)免費(fèi)試用、咨詢電話:400-8352-114
AMTeam.orgWeb Service Case Study: 事務(wù)性Web服務(wù)
柴曉路 (fennivel@uddi-china.org)
Chief System
Architect
2002年4月26日
本文是Web Service Case
Study系列文章的第三篇。在這篇文章中,我將圍繞一個(gè)事務(wù)性應(yīng)用展開討論,探討在Web服務(wù)環(huán)境中實(shí)現(xiàn)原先在數(shù)據(jù)庫層次或者對(duì)象層次中實(shí)現(xiàn)的事務(wù)特性。具體的,這里的應(yīng)用實(shí)例是一個(gè)分布式的數(shù)據(jù)庫同步的應(yīng)用,我們需要解決的是在多個(gè)分布在Internet上的同構(gòu)數(shù)據(jù)庫完成增量式的基于事務(wù)的數(shù)據(jù)同步問題。
應(yīng)用背景
以下描述中使用的地名、機(jī)構(gòu)名和系統(tǒng)名稱純屬虛構(gòu),但是是從具體應(yīng)用中抽象出來的。
Briliiance City是一個(gè)醫(yī)療保健公眾服務(wù)正處于建設(shè)中的城市。市政府的最終目標(biāo)是將整個(gè)城市的醫(yī)療機(jī)構(gòu)(包括綜合性大型醫(yī)院、專業(yè)醫(yī)院、分區(qū)醫(yī)院等)、健康保健機(jī)構(gòu)(社區(qū)醫(yī)院、社區(qū)醫(yī)生)等等通過Internet聯(lián)系在一起,從而實(shí)現(xiàn)將市民的醫(yī)療記錄和健康保健記錄統(tǒng)一管理。具體的來看,這個(gè)公眾服務(wù)網(wǎng)絡(luò)最終需要具備以下特性:
一致的邏輯數(shù)據(jù):對(duì)于每個(gè)市民而言,他的醫(yī)療記錄和保健記錄在邏輯上由這個(gè)服務(wù)網(wǎng)絡(luò)統(tǒng)一管理,從任意的服務(wù)結(jié)點(diǎn)(任何醫(yī)療機(jī)構(gòu)或是健康保健機(jī)構(gòu))獲得的個(gè)人數(shù)據(jù)都應(yīng)該是一致的,也就是說,從邏輯上,整個(gè)服務(wù)網(wǎng)絡(luò)只有一個(gè)市民個(gè)人醫(yī)療保健信息數(shù)據(jù)庫,而所有的服務(wù)結(jié)點(diǎn)都是這個(gè)數(shù)據(jù)庫的客戶端應(yīng)用。
優(yōu)秀的網(wǎng)絡(luò)環(huán)境的適應(yīng)性:由于整個(gè)城市的基礎(chǔ)設(shè)置,尤其是網(wǎng)絡(luò)基礎(chǔ)設(shè)施尚不是非常出色,雖然每個(gè)機(jī)構(gòu)都能夠連上Internet,但是除了一些比較大的機(jī)構(gòu),諸如綜合性大型醫(yī)院、專業(yè)醫(yī)院、社區(qū)醫(yī)院等能夠使用寬帶,并一直在線以外,相當(dāng)多的機(jī)構(gòu)還是在普遍使用撥號(hào)上網(wǎng)的方式。同時(shí)有些機(jī)構(gòu)的上網(wǎng)方式是能夠獲得公網(wǎng)IP的,而有些則沒有公網(wǎng)IP。從系統(tǒng)的實(shí)現(xiàn)角度來考慮,我們的服務(wù)網(wǎng)絡(luò)需要滿足這些復(fù)雜的網(wǎng)絡(luò)環(huán)境。
機(jī)構(gòu)系統(tǒng)的兼容性:由于服務(wù)結(jié)點(diǎn)的數(shù)量巨大,其使用的平臺(tái)和語言各不相同,這個(gè)服務(wù)網(wǎng)絡(luò)需要能夠容納所有類型的服務(wù)結(jié)點(diǎn)。
開放的界面和接口:由于這是一個(gè)公共服務(wù),因此不僅個(gè)人用戶能夠方便地通過Web或者桌面應(yīng)用查詢個(gè)人的醫(yī)療保健信息,同時(shí)也需要提供非GUI的交互界面,以便使企業(yè)應(yīng)用或者其他政府應(yīng)用可以使用這個(gè)醫(yī)療保健網(wǎng)絡(luò)服務(wù)所能提供的信息。
目前,在Brilliance City的東城區(qū),大部分醫(yī)療保健機(jī)構(gòu)都采用了一家稱為Health
Inside的軟件公司的產(chǎn)品部署了各自的應(yīng)用系統(tǒng),包括醫(yī)院信息系統(tǒng)、醫(yī)療保健系統(tǒng)等等。由于采用了同一家公司的產(chǎn)品,因此他們?cè)诘讓訑?shù)據(jù)層的設(shè)計(jì)是基本一致的,市政府打算以此為試點(diǎn),如果應(yīng)用情況良好再推廣到全市。
解決方案
根據(jù)整個(gè)服務(wù)網(wǎng)絡(luò)的應(yīng)用背景,我們?cè)O(shè)計(jì)了這樣一個(gè)解決方案:一個(gè)分布式的醫(yī)療保健的信息服務(wù)網(wǎng)絡(luò)。具體描述如下:
數(shù)據(jù)邏輯集中,物理分布
在這個(gè)服務(wù)網(wǎng)絡(luò)中,數(shù)據(jù)仍然被保存在各個(gè)服務(wù)結(jié)點(diǎn),對(duì)于這樣一個(gè)Internet環(huán)境下的應(yīng)用而言,數(shù)據(jù)庫集中是無法想象的,Internet不可能永遠(yuǎn)穩(wěn)定工作,其次如果采取數(shù)據(jù)庫集中,骨干網(wǎng)上的流量也是無法接收的。由于數(shù)據(jù)是物理分布的,而邏輯上只有一個(gè)合法版本的數(shù)據(jù),因此我們需要有跨結(jié)點(diǎn)的分布式數(shù)據(jù)同步機(jī)制來保障數(shù)據(jù)的一致性。
數(shù)據(jù)同步的事務(wù)性
當(dāng)一個(gè)服務(wù)結(jié)點(diǎn)執(zhí)行了某個(gè)事務(wù)之后,為了完成數(shù)據(jù)同步,我們需要把這個(gè)事務(wù)在其他相關(guān)的服務(wù)結(jié)點(diǎn)上也同樣加以運(yùn)行,由于數(shù)據(jù)之間具有關(guān)聯(lián)性,因此在其他結(jié)點(diǎn)上的運(yùn)行必須同樣保證事務(wù)性。
通過交換中心的消息隊(duì)列傳輸
由于各個(gè)服務(wù)結(jié)點(diǎn)的聯(lián)網(wǎng)狀況比較復(fù)雜,很多結(jié)點(diǎn)都無法一直保持在線的狀態(tài),因此使用消息隊(duì)列來傳遞事務(wù)將比較有效。我們?cè)O(shè)置了一個(gè)用于交換事務(wù)數(shù)據(jù)的交換中心,在交換中心上為每個(gè)服務(wù)結(jié)點(diǎn)提供了in/out消息隊(duì)列。交換中心是部署在Internet主干上的,因此只要服務(wù)結(jié)點(diǎn)連上了Internet,就可以通過交換中心收發(fā)包含事務(wù)的消息。
從數(shù)據(jù)庫模式到邏輯數(shù)據(jù)模式
整個(gè)系統(tǒng)的實(shí)施將分布走,首先先將服務(wù)網(wǎng)絡(luò)覆蓋到Health Inside的客戶,此時(shí)由于所有服務(wù)結(jié)點(diǎn)都是同構(gòu)系統(tǒng),因此我們一開始事務(wù)是基于數(shù)據(jù)庫模式的,也就是歸根于數(shù)據(jù)庫表記錄的增刪改等。隨后將慢慢地延伸到其他公司的產(chǎn)品或解決方案,此時(shí)基于數(shù)據(jù)庫模式的事務(wù)將不在有效,需要就市民的醫(yī)療保健記錄及其操作制訂基于XML的業(yè)務(wù)事務(wù)規(guī)范,所有的事務(wù)都將基于這樣的格式進(jìn)行傳播,此時(shí)在各個(gè)服務(wù)結(jié)點(diǎn)就需要有一個(gè)從基于數(shù)據(jù)庫模式的事務(wù)到基于XML數(shù)據(jù)模式的業(yè)務(wù)事務(wù)。為了在這個(gè)轉(zhuǎn)換過程中減少代價(jià),降低風(fēng)險(xiǎn),我們?cè)谝婚_始的基于數(shù)據(jù)庫模式的事務(wù)消息交換時(shí),同樣使用XML來描述事務(wù),使用Web服務(wù)架構(gòu)來構(gòu)建交換中心。如此,待服務(wù)網(wǎng)絡(luò)向其他類型的系統(tǒng)延伸的時(shí)候,對(duì)于服務(wù)網(wǎng)絡(luò)而言,基本無需更新,工作量集中在每個(gè)服務(wù)結(jié)點(diǎn)的數(shù)據(jù)庫模式向業(yè)務(wù)模式的轉(zhuǎn)化,以及服務(wù)結(jié)點(diǎn)接入服務(wù)網(wǎng)絡(luò)兩大塊。前者是面向業(yè)務(wù)的,工作量無法節(jié)約。而后者由于采用了Web服務(wù)架構(gòu),可以通過Web服務(wù)的規(guī)范協(xié)議方便地構(gòu)筑系統(tǒng)交互。
基于數(shù)據(jù)中心的公共界面
在這個(gè)服務(wù)網(wǎng)絡(luò)中,除交換中心外,我們還設(shè)置了一個(gè)數(shù)據(jù)中心,設(shè)置的目的是多方面的。第一個(gè)目的是為統(tǒng)一管理市民的基本信息,從這個(gè)意義上將,數(shù)據(jù)中心也是一種服務(wù)結(jié)點(diǎn),在數(shù)據(jù)中心上對(duì)市民信息進(jìn)行更新,同樣需要通過數(shù)據(jù)同步和消息隊(duì)列的機(jī)制將這一更新事務(wù)傳遞到其他相關(guān)的服務(wù)結(jié)點(diǎn)。第二個(gè)目的是為對(duì)外的面向市民、面向企業(yè)的公共服務(wù)提供數(shù)據(jù),如此就無需在運(yùn)行時(shí)刻頻繁地對(duì)各個(gè)服務(wù)結(jié)點(diǎn)進(jìn)行數(shù)據(jù)請(qǐng)求。同時(shí),當(dāng)某個(gè)服務(wù)結(jié)點(diǎn)崩潰,需要重建的時(shí)候,可以從數(shù)據(jù)中心下載所有其管理和使用的數(shù)據(jù)。
體系架構(gòu)
Figure 1. 體系架構(gòu)圖示
這個(gè)服務(wù)網(wǎng)絡(luò)的基本體系架構(gòu)可參見上圖。其技術(shù)核心就是各個(gè)服務(wù)結(jié)點(diǎn)之間的數(shù)據(jù)同步事務(wù)的實(shí)現(xiàn)。而這一機(jī)制的實(shí)現(xiàn),在服務(wù)網(wǎng)絡(luò)的第一期目標(biāo)下,基本可以歸結(jié)為兩點(diǎn):
數(shù)據(jù)庫事務(wù)的XML表示
在Web服務(wù)環(huán)境下事務(wù)性的保證
數(shù)據(jù)庫事務(wù)的XML表示
由于在第一期工程中,所有的服務(wù)節(jié)點(diǎn)是同構(gòu)系統(tǒng),使用了相同的數(shù)據(jù)庫結(jié)構(gòu),而且為了最大化地減小每個(gè)服務(wù)節(jié)點(diǎn)的實(shí)現(xiàn)代價(jià),因此我們采用了完全基于數(shù)據(jù)庫事務(wù)的數(shù)據(jù)同步方式。每條數(shù)據(jù)同步消息將包含一個(gè)事務(wù)(transaction)的描述,而一個(gè)事務(wù)可以包含多個(gè)操作(operation),每個(gè)操作要么是在某張表中更新(或添加)記錄,或是在某張表中刪除記錄。
根據(jù)這樣的設(shè)計(jì)思想,我們可以定義了transaction元素(包括其子元素)來表示一個(gè)事務(wù)消息,具體的Schema定義如下:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
targetNamespace="urn:dealeasy:webservice:exchange:schema"
xmlns="dealeasy:webservice:exchange:schema"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:complexType name="field">
<xs:sequence>
<xs:element name="name"
type="xs:string"/>
<xs:element
name="type" type="xs:string"/>
<xs:element name="value" type="xs:base64Binary"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="primaryKey">
<xs:sequence>
<xs:element
name="field" type="field" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="allField">
<xs:sequence>
<xs:element
name="field" type="field"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="save_data">
<xs:sequence>
<xs:element
name="tableName" type="xs:string"/>
<xs:element name="primaryKey"
type="primaryKey"/>
<xs:element
name="allField" type="allField" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="delete_data">
<xs:sequence>
<xs:element
name="tableName" type="xs:string"/>
<xs:element name="primaryKey" type="primaryKey"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="operations">
<xs:sequence>
<xs:element
name="save_data" type="save_data"
minOccurs="0"
maxOccurs="unbounded"/>
<xs:element
name="delete_data" type="delete_data"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="transaction">
<xs:sequence>
<xs:element
name="operations" type="operations"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
在這個(gè)模式定義中,核心是對(duì)數(shù)據(jù)的操作,這里為簡便性起見,僅僅定義了兩個(gè)操作save_data和delete_data,這也是符合國際慣例的定義。理由是,新增數(shù)據(jù)(記錄級(jí))和更新數(shù)據(jù)(記錄級(jí))可以使用相同的調(diào)用。相似的模式定義我在本系列的第一篇文章中已經(jīng)提及。
這里采用的描述方法是針對(duì)通用的數(shù)據(jù)庫操作的,也就是說無論具體數(shù)據(jù)庫的結(jié)構(gòu)如何,只要每個(gè)端系統(tǒng)都是相同的,那么這個(gè)消息模式就可以應(yīng)用。在save_data元素下,包含了三個(gè)元素:
tableName,這個(gè)元素指明了需要操作的記錄所在的數(shù)據(jù)庫表(Table)的名字;
primaryKey,這個(gè)元素用于描述待操作的數(shù)據(jù)記錄(record)的主鍵,系統(tǒng)通過這個(gè)主鍵可以準(zhǔn)確定位到需要操作的記錄(Record),如果沒有找到由該主鍵標(biāo)識(shí)的記錄,那么對(duì)應(yīng)的操作就是新增記錄(insert
record),如果找到了由該主鍵標(biāo)識(shí)的記錄,那么對(duì)應(yīng)的操作就是更新記錄(update record);
allField,這個(gè)元素用于描述待操作的數(shù)據(jù)記錄中除主鍵字段外的所有字段,值得注意的是主鍵字段也可以是多個(gè)的。
而對(duì)于delete_data,其結(jié)構(gòu)與save_data是類似的,唯一的差別就是沒有allField元素,原因相信大家也很容易理解,在刪除數(shù)據(jù)時(shí),只要知道主鍵就足夠了。
有了Schema的模式定義文檔,我們就能夠生成SOAP消息了,下面首先給出的是一個(gè)由單個(gè)save_data操作和單個(gè)delete_data操作組成的事務(wù)的例子。該事務(wù)從candidate_employee中刪除一條記錄,而在employee中添加了一條記錄。
<env:Envelope
xmlns:env="http://www.w3.org/2001/06/soap-envelope"
env:encodingStyle="http://www.w3.org/2001/06/soap-encoding">
<env:Body>
<transaction:transaction
xmlns:po="Some-URI">
<operations>
<delete_data>
<tableName>candidate_employee</tableName>
<primaryKey>
<field>
<name>id</name>
<type>uuid</type>
<value>crystal</value>
</field>
</primaryKey>
</delete_data>
<save_data>
<tableName>employee</tableName>
<primaryKey>
<field>
<name>id</name>
<type>uuid</type>
<value>crystal</value>
</field>
</primaryKey>
<allField>
<field>
<name>name</name>
<type>string</type>
<value>Crystal
Zhuang</value>
</field>
<field>
<name>gender</name>
<type>string</type>
<value>female</value>
</field>
<field>
<name>email</name>
<type>string</type>
<value>crystalzh@email.com</value>
</field>
</allField>
</save_data>
</operations>
</transaction:transaction>
</env:Body>
</env:Envelope>
事務(wù)性的保證
由于我們使用Web服務(wù)架構(gòu)來架構(gòu)我們的交換中心。因此在我們定義好了事務(wù)消息的XML描述之后,就需要實(shí)施如何通過SOAP消息來傳輸所需要傳播的事務(wù)消息了。對(duì)于這個(gè)服務(wù)網(wǎng)絡(luò)而言,其核心問題就是要將服務(wù)節(jié)點(diǎn)的事務(wù)(目前是數(shù)據(jù)庫事務(wù),以后將延伸到業(yè)務(wù)事務(wù))在各個(gè)相應(yīng)的服務(wù)結(jié)點(diǎn)上同樣以滿足事務(wù)性的條件下執(zhí)行。由于我們采用的是Web服務(wù)架構(gòu),Web服務(wù)架構(gòu)的現(xiàn)有技術(shù)中尚未有正式的支持事務(wù)的規(guī)范或技術(shù)。因此在這部分,我們將首先圍繞當(dāng)前這個(gè)服務(wù)網(wǎng)絡(luò)中的應(yīng)用來討論Web服務(wù)的事務(wù)性,當(dāng)解決了當(dāng)前這個(gè)應(yīng)用實(shí)例中的問題之后,我們將從通用全面的角度繼續(xù)考察更復(fù)雜情況下的Web服務(wù)事務(wù)性的保證。
最簡單的情況
如果我們?cè)趥鬏斒聞?wù)消息的時(shí)候,總能保證單個(gè)事務(wù)消息使用單個(gè)SOAP消息來傳輸?shù)脑挘敲催@就是最簡單的情況。此時(shí),SOAP僅僅是傳輸事務(wù)數(shù)據(jù)的機(jī)制,而并不包含事務(wù)控制的功能。
具體的流程可以描述如下:
服務(wù)結(jié)點(diǎn)A完成了數(shù)據(jù)庫事務(wù)T,事務(wù)處理模塊使用我們先前制訂的XML模式將事務(wù)T表示為XML格式T(XML)。
服務(wù)結(jié)點(diǎn)A的SOAP Service將T(XML)包裝在SOAP
Body里面,組成SOAP消息,向交換中心發(fā)送,此時(shí)消息在交換中心中位于服務(wù)結(jié)點(diǎn)A的"out"消息隊(duì)列中。
交換中心獲得服務(wù)結(jié)點(diǎn)A的"out"消息隊(duì)列中的事務(wù)消息,并分析出與之相關(guān)的需要實(shí)施事務(wù)同步的服務(wù)結(jié)點(diǎn)集合(假設(shè)在這里我們僅找到一個(gè)相關(guān)的服務(wù)結(jié)點(diǎn)B)。
交換中心將這則事務(wù)消息T(XML)復(fù)制到服務(wù)結(jié)點(diǎn)B的"in"消息隊(duì)列(當(dāng)然也可以不復(fù)制,而采取指針的方式,不過采取這種方式的話,在維護(hù)方面的復(fù)雜度會(huì)有稍許的提高)。
服務(wù)結(jié)點(diǎn)B上線之后,檢查交換中心的消息隊(duì)列,獲得事務(wù)消息,在SOAP
Service中將T(XML)從SOAP消息中剝離并交給下層的事務(wù)處理模塊。
服務(wù)結(jié)點(diǎn)B的事務(wù)處理模塊將T(XML)通過XML解析,轉(zhuǎn)換成內(nèi)部的事務(wù),并實(shí)施運(yùn)行。
從單條消息到多條消息
然而,并不是在任何情況下,使用一條SOAP消息就能夠傳輸一則事務(wù)的。由于SOAP消息最終是要和某一種網(wǎng)絡(luò)協(xié)議進(jìn)行綁定并在網(wǎng)絡(luò)上進(jìn)行傳輸?shù)?,大多?shù)網(wǎng)絡(luò)連接很難保證在一個(gè)連接內(nèi)能穩(wěn)定地傳輸大量的數(shù)據(jù),比如HTTP,我們?cè)谙螺d/上傳大文件的時(shí)候,經(jīng)常會(huì)發(fā)生中斷,此時(shí)我們就不得不重傳(HTTP沒有斷點(diǎn)續(xù)傳),重傳需要耗費(fèi)同樣長的時(shí)間,同時(shí)傳輸時(shí)間越長發(fā)生錯(cuò)誤的可能也越大,因此傳輸大文件如果不加以特別的措施的話,常常會(huì)變成一場噩夢(mèng)。我們通常的方法,是將大文件分割成多個(gè)小塊,分別傳輸,等全部傳輸完畢后在對(duì)等方組合。由于單個(gè)文件塊比較小,傳輸穩(wěn)定性得到了提升,同時(shí)即使傳輸失敗,重傳的話也比較快。
我們將這一用于文件傳輸?shù)姆椒?,延伸到事?wù)消息的傳輸中,由于這是一個(gè)平臺(tái)級(jí)的特性,因此我們按照SOAP規(guī)范的推薦,使用SOAP Header來控制事務(wù)消息的合并執(zhí)行,同時(shí)為了提高響應(yīng)率,我們的算法并不一定要等到關(guān)聯(lián)單個(gè)事務(wù)的消息全部收到才會(huì)執(zhí)行事務(wù),我們采取了一定地提前執(zhí)行的機(jī)制,具體細(xì)節(jié),我將在下面詳細(xì)闡述。
首先我們給出transactionControl這個(gè)SOAP Header Extension的模式定義。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="transactionControl"
type="transactionControl"/>
<xs:complexType
name="transactionControl">
<xs:sequence>
<xs:element
name="simpleTransaction" type="simpleTransaction"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="simpleTransaction">
<xs:sequence>
<xs:element
name="transactionID" type="xs:string"/>
<xs:element name="begin" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="commit" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="rollback" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element name="part"
type="xs:integer" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
在這個(gè)模式定義中,我們看到transactionControl這個(gè)SOAP Header Extension包含了一個(gè)子元素simpleTransaction,我們?cè)谙旅婢褪褂眠@個(gè)子元素來描述事務(wù)消息,為是么不直接使用transactionControl元素,而要在其下再定義一層子元素,是為了以后對(duì)事務(wù)控制特性進(jìn)行進(jìn)一步的擴(kuò)展,我們會(huì)在這基礎(chǔ)上實(shí)現(xiàn)兩階段提交和三階段提交等。
simpleTransaction元素包含了五個(gè)子元素:transactionID、begin、commit、rollback和part。他們的含義分別如下:
transactionID:事務(wù)的標(biāo)識(shí)ID,兩個(gè)描述事務(wù)的SOAP消息當(dāng)切僅當(dāng)具備相同的transactionID時(shí),我們才認(rèn)為他們是一個(gè)事務(wù)的兩個(gè)組成部分。
begin:表示事務(wù)可以開始執(zhí)行。
commit:表示事務(wù)可以提交。
rollback:表示事務(wù)可以回滾。
part:這是一個(gè)整數(shù)類型的值,表示SOAP
Body中的內(nèi)容是當(dāng)前事務(wù)的第幾個(gè)部分,整個(gè)事務(wù)應(yīng)當(dāng)按照part值所描述的順序依次執(zhí)行。
由于這五個(gè)子元素可能同時(shí)出現(xiàn)(rollback和commit不會(huì)同時(shí)出現(xiàn)),當(dāng)服務(wù)結(jié)點(diǎn)接受到事務(wù)消息時(shí),上述的五個(gè)子元素被解釋執(zhí)行的先后次序?yàn)椋簍ransactionID、begin、part(觸發(fā)解析SOAP
Body)、commit & rollback。他們的工作原理可描述如下:
當(dāng)服務(wù)結(jié)點(diǎn)受到一個(gè)事務(wù)SOAP消息之后,首先解析出transactionID,如果是新的transactionID,那么在服務(wù)器端的事務(wù)池中,新建一個(gè)事務(wù),并將transactionID賦予之。如果事務(wù)池中已經(jīng)有了這個(gè)transactionID,那么就將這個(gè)事務(wù)消息與之關(guān)聯(lián)。當(dāng)完成transactionID的識(shí)別之后,如果消息中帶有begin,那么就啟動(dòng)這個(gè)被關(guān)聯(lián)的事務(wù)池中的事務(wù)。如果消息中帶有part,假設(shè)part的值為n:
將當(dāng)前消息的SOAP Body作為事務(wù)的第n部分存入事務(wù)的緩存控件;
檢查當(dāng)前事務(wù)的緩存空間,如果發(fā)現(xiàn)已經(jīng)包含了1到m之間所有的事務(wù)部分,那么就依次執(zhí)行從1到m之間所有未執(zhí)行的事務(wù)部分。
如果消息中帶有commit,那么在緩存事務(wù)部分的時(shí)候(這一定是最后一個(gè)事務(wù)部分),對(duì)其加上標(biāo)志:"這是該事務(wù)的最后一個(gè)部分"。當(dāng)該部分被執(zhí)行時(shí),整個(gè)事務(wù)將被提交。
如果消息中帶有rollback,那么對(duì)應(yīng)的事務(wù)被立即回滾,然后該事務(wù)失效,如果之后仍然收到該事務(wù)空間中的消息的話,服務(wù)結(jié)點(diǎn)將丟棄這些消息。
例如:服務(wù)結(jié)點(diǎn)可能以如下次序接受到關(guān)聯(lián)同一事務(wù)的事務(wù)消息:
[part(2)], [part(4)], [begin,part(1)], [part(3)], [commit, part(6)], [part(5)]
那么服務(wù)結(jié)點(diǎn)的動(dòng)作序列應(yīng)當(dāng)為:
接收到[part(2)],在事務(wù)池中創(chuàng)建一個(gè)事務(wù)空間,并緩存該事務(wù)部分,現(xiàn)在緩存為(2);
接收到[part(4)],緩存該事務(wù)部分,現(xiàn)在緩存為(2, 4);
接收到[begin,part(1)],啟動(dòng)事務(wù),緩存該事務(wù)部分,現(xiàn)在緩存為(1, 2, 4),事務(wù)1,2兩個(gè)部分被執(zhí)行;
接收到[part(3)],緩存該事務(wù)部分,現(xiàn)在緩存為(…, 3, 4),事務(wù)3,4兩個(gè)部分被執(zhí)行;
接收到[commit,
part(6)],緩存該事務(wù)部分,現(xiàn)在緩存為(…, 6),同時(shí)第6部分被置commit標(biāo)志;
接收到[part(5)],緩存該事務(wù)部分,現(xiàn)在緩存為(…, 5, 6),事務(wù)5,6兩個(gè)部分被執(zhí)行,然后事務(wù)被提交。
在這一節(jié)中介紹的方法解決了在分布式的環(huán)境中,在單點(diǎn)數(shù)據(jù)庫中完成了事務(wù)的執(zhí)行。這個(gè)機(jī)制有效的解決了我們這個(gè)服務(wù)網(wǎng)絡(luò)應(yīng)用實(shí)例的當(dāng)前需求。
然而,我們考慮到,在將來整個(gè)服務(wù)網(wǎng)絡(luò)將向公眾開放,包括個(gè)人用戶和企業(yè)用戶在內(nèi)的各種用戶都可以訪問和使用服務(wù)網(wǎng)絡(luò)。雖然一開始只有一些數(shù)據(jù)查詢的事務(wù)開放給他們使用,不過隨著整個(gè)服務(wù)網(wǎng)絡(luò)的成熟,我們將會(huì)在數(shù)據(jù)中心層次上對(duì)外提供業(yè)務(wù)處理服務(wù),而這些服務(wù)被使用時(shí),勢(shì)必發(fā)生一些業(yè)務(wù)事務(wù),根據(jù)整個(gè)服務(wù)網(wǎng)絡(luò)的設(shè)計(jì)原則,這些業(yè)務(wù)事務(wù)需要在整個(gè)服務(wù)網(wǎng)絡(luò)上被執(zhí)行,在這種情況下,與前面我們介紹的單個(gè)事務(wù)的重復(fù)廣播有所不同,這里發(fā)生的是一個(gè)涉及到多個(gè)服務(wù)結(jié)點(diǎn)的分布式事務(wù)。例如:這個(gè)事務(wù)可能同時(shí)涉及某個(gè)市民的醫(yī)療記錄和保健記錄,而這兩者分別是由兩個(gè)服務(wù)結(jié)點(diǎn)來管理的。前面的機(jī)制已經(jīng)無法解決這一問題,下面我們將兩階段提交協(xié)議(2PC)引入到我們的Web服務(wù)環(huán)境中來,以嘗試解決這一分布式事務(wù)的問題。
兩階段提交(Two-Phase Commit)
兩階段提交。分布式系統(tǒng)中處理用戶提交的事務(wù)時(shí),事務(wù)管理器通常使用兩階段提交協(xié)議保證所有操作所涉及到的分布式環(huán)境中的各個(gè)數(shù)據(jù)庫中的相應(yīng)數(shù)據(jù)被鎖定從而最后被正確地更新。如果因?yàn)槟撤N原因操作不能完成,則要求統(tǒng)一執(zhí)行"回滾"操作,回到事務(wù)開始前的狀態(tài)。如果事務(wù)被成功執(zhí)行,那么所有相關(guān)的數(shù)據(jù)庫都被正確更新,此時(shí)這些更新應(yīng)當(dāng)被分布式環(huán)境中的所有數(shù)據(jù)庫系統(tǒng)都了解。最后解除相關(guān)數(shù)據(jù)庫重相關(guān)數(shù)據(jù)的鎖定狀態(tài),以便進(jìn)行下一個(gè)事務(wù)的執(zhí)行。
以下我們描述一個(gè)擴(kuò)展的兩階段提交的協(xié)議過程(這個(gè)擴(kuò)展的2PC比標(biāo)準(zhǔn)的2PC多了預(yù)先準(zhǔn)備的三個(gè)步驟,也被稱為3PC):
事務(wù)管理器部署在中央服務(wù)器上,它處于中心控制結(jié)點(diǎn)的位置,以事務(wù)發(fā)起者的身份開始工作,它首先在事務(wù)管理器日志中寫入一條"Prepare
Transaction"的記錄,然后將相應(yīng)的事務(wù)請(qǐng)求發(fā)送到所有相關(guān)的服務(wù)結(jié)點(diǎn)(需要執(zhí)行事務(wù)的部分)上。
當(dāng)每個(gè)參與事務(wù)的服務(wù)結(jié)點(diǎn)接收到"Prepare
Transaction",服務(wù)結(jié)點(diǎn)可以按照自己的負(fù)載狀況選擇是"Accept"還是"Reject",并將"Accept"或"Reject"消息發(fā)回事務(wù)管理器。
當(dāng)事務(wù)管理器收到所有服務(wù)結(jié)點(diǎn)的響應(yīng)后,如果全部都是"Accept"消息,那么繼續(xù)下一步。如果至少有一個(gè)服務(wù)結(jié)點(diǎn)返回的是"Reject"消息,那么這個(gè)事務(wù)將不會(huì)真正開始,事務(wù)結(jié)束。當(dāng)然,在處理"Reject"消息的時(shí)候,可以有一些優(yōu)化的方法,我們可以在收到第一條"Reject"消息的時(shí)候,即時(shí)將事務(wù)結(jié)束(當(dāng)然也可以選擇緩存在隊(duì)列里,等過一段時(shí)間后重試),并且丟棄以后收到的和這個(gè)事務(wù)相關(guān)的"Accept"或"Reject"消息。
當(dāng)所有服務(wù)結(jié)點(diǎn)發(fā)回"Accept"消息后,事務(wù)管理器準(zhǔn)備真正開始執(zhí)行事務(wù)。它在事務(wù)管理器日志中寫入一條"Begin
Transaction"的記錄,然后將相應(yīng)的事務(wù)執(zhí)行內(nèi)容發(fā)送給所有相關(guān)的服務(wù)結(jié)點(diǎn)。
各個(gè)服務(wù)結(jié)點(diǎn)將此事務(wù)寫入自己的日志,然后鎖定資源以供該事務(wù)使用,當(dāng)資源準(zhǔn)備完畢后,服務(wù)結(jié)點(diǎn)向事務(wù)管理器所在的計(jì)算機(jī)發(fā)送"Ready"消息。
當(dāng)事務(wù)管理器所在的中心控制結(jié)點(diǎn)接收到所有的"Ready"消息后(即參與事務(wù)的所有服務(wù)結(jié)點(diǎn)都必須發(fā)回"Ready"信息),它在日志上記錄"Commit
Transaction",要求該事務(wù)被提交,并通知所有相關(guān)的服務(wù)結(jié)點(diǎn)。如果在一定的時(shí)間內(nèi),至少有一個(gè)服務(wù)結(jié)點(diǎn)沒有返回"Ready"信息,那么它視該事務(wù)執(zhí)行失敗。將會(huì)在日志上記錄"Rollback
Transaction",并發(fā)送給所有服務(wù)結(jié)點(diǎn),要求回滾事務(wù),并將該事務(wù)結(jié)束。
當(dāng)這些相關(guān)的服務(wù)結(jié)點(diǎn)接收到"Commit
Transaction"通知后,這些服務(wù)結(jié)點(diǎn)將自身承擔(dān)的事務(wù)部分提交(Commit),并解除對(duì)資源的鎖定,同時(shí)通知事務(wù)管理器執(zhí)行完畢。
如果服務(wù)結(jié)點(diǎn)接收到"Rollback
Transaction"通知后,這些服務(wù)結(jié)點(diǎn)將自身承擔(dān)的事務(wù)部分回滾(Rollback),并解除對(duì)資源的鎖定。
在這里,我們有兩個(gè)假設(shè):
事務(wù)管理器總是工作正常的,否則服務(wù)結(jié)點(diǎn)在無限期等待事務(wù)管理器的"Commit"或"Rollback"消息時(shí),將處于無法工作狀態(tài),因?yàn)榉?wù)結(jié)點(diǎn)是不能自主地選擇提交或是回滾的,否則就有可能與其他服務(wù)結(jié)點(diǎn)的數(shù)據(jù)不再同步。此時(shí)其他服務(wù)結(jié)點(diǎn)可能已經(jīng)提交或者回滾了。
當(dāng)服務(wù)結(jié)點(diǎn)鎖定事務(wù)執(zhí)行時(shí)需要的資源,并且發(fā)送了"Ready"消息之后,我們只能認(rèn)為他一定能完成事務(wù)的執(zhí)行,否則如果在提交階段發(fā)生錯(cuò)誤,很可能其他結(jié)點(diǎn)已經(jīng)提交了,提交了的事務(wù)是無法回滾的。
在仔細(xì)地分析了兩階段提交之后,我們來擴(kuò)展先前定義的transactionControl元素,為這個(gè)SOAP Header
Extension增加新的功能。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="transactionControl"
type="transactionControl"/>
<xs:complexType
name="transactionControl">
<xs:sequence>
<xs:element
name="transactionID" type="xs:string"/>
<xs:element name="simpleTransaction" type="simpleTransaction"
minOccurs="0"/>
<xs:element
name="twoPhaseCommitTransaction" type="twoPhaseCommitTransaction"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType
name="simpleTransaction">
<xs:sequence>
<xs:element
name="begin" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="commit" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element
name="rollback" type="xs:boolean" nillable="true"
minOccurs="0"/>
<xs:element name="part"
type="xs:integer" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="twoPhaseCommitTransaction">
<xs:sequence>
<xs:element
name="serviceNode" type="xs:string"/>
<xs:element name="prepare"
minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="request" type="xs:string" nillable="true"
minOccurs="0"/>
<xs:element name="response" type="xs:string"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element
name="begin" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="request" nillable="true"
minOccurs="0"/>
<xs:element name="part"
minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension
base="xs:integer">
<xs:attribute name="final"
type="xs:boolean"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="response" type="xs:string"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element
name="rollback" minOccurs="0"/>
<xs:element name="commit" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
simpleTransaction那部分基本上沒有什么大的變化,只是將transactionID提取到transactionControl下,以供公共使用。而twoPhaseCommit元素就是供我們描述的擴(kuò)展兩階段提交協(xié)議使用。
twoPhaseCommit元素共有以下子元素:serviceNode元素、prepare元素、begin元素、rollback元素和submit元素。我們下面來分別講解這幾個(gè)元素的用途:
serviceNode元素:描述服務(wù)結(jié)點(diǎn)的標(biāo)識(shí),該元素的值唯一標(biāo)識(shí)了一個(gè)服務(wù)結(jié)點(diǎn)。
prepare元素:完成"Prepare Transaction"階段的交互。事務(wù)管理器發(fā)出的"Prepare
Transaction"消息是使用prepare元素及其子元素request來表示,同時(shí)如果發(fā)往服務(wù)結(jié)點(diǎn)A,那么該消息中的serviceNode元素取值也應(yīng)該是A。而服務(wù)結(jié)點(diǎn)對(duì)"Prepare
Transaction"消息的響應(yīng)則是使用prepare元素及其子元素response來表示,具體的response元素的值是"accept"表示可以執(zhí)行事務(wù),如果是"reject"則表示不能執(zhí)行事務(wù)。同樣,服務(wù)結(jié)點(diǎn)A發(fā)回的響應(yīng)消息,則消息中的serviceNode元素取值也應(yīng)該是A。
begin元素:完成"Begin Transaction"階段的交互。事務(wù)管理器發(fā)出的"Begin
Transaction"消息是使用begin元素及其子元素request來表示。事務(wù)管理器發(fā)出的描述事務(wù)內(nèi)容的消息應(yīng)當(dāng)使用begin元素的子元素part來表示,part中的數(shù)值為其在事務(wù)內(nèi)容消息序列中的序號(hào),而此時(shí)SOAP
Body中的內(nèi)容就是相應(yīng)的事務(wù)內(nèi)容。這一分塊傳輸?shù)臋C(jī)制與先前的simpleTransaction中描述的是類似的,其中最后一則消息分塊的part元素應(yīng)當(dāng)帶有值為"true"的final屬性(參照前面的模式文檔,part元素可帶有一個(gè)屬性final,
final的類型是xs:boolean)。當(dāng)服務(wù)結(jié)點(diǎn)接收到所有的消息分塊后,即申請(qǐng)所有所需的資源,并使用begin元素及其子元素response來響應(yīng)。如果資源申請(qǐng)成功,則response的值為"ready",否則則為"failure"。
rollback元素:如果某個(gè)服務(wù)結(jié)點(diǎn)返回的begin/response的值為"failure",那么事務(wù)管理器就需要向每個(gè)服務(wù)結(jié)點(diǎn)發(fā)送rollback消息。
commit元素,如果每個(gè)服務(wù)結(jié)點(diǎn)返回的begin/response的值都是"ready",那么事務(wù)管理器就需要向每個(gè)服務(wù)結(jié)點(diǎn)發(fā)送commit消息。
下面我們給出一個(gè)消息序列來解釋這些元素的使用方式,這個(gè)消息序列的應(yīng)用背景是一個(gè)涉及兩個(gè)服務(wù)結(jié)點(diǎn)A、B的事務(wù)執(zhí)行。
未完待續(xù)
在本文章系列的第三篇中,我們借助一個(gè)服務(wù)網(wǎng)絡(luò)的案例來分析了Web服務(wù)事務(wù)性的實(shí)現(xiàn),前面我們討論了Web服務(wù)環(huán)境下的簡單的事務(wù)廣播,以及分布式事務(wù)的擴(kuò)展的兩階段提交模型的實(shí)現(xiàn)。然而大家應(yīng)該發(fā)現(xiàn),首先,這樣的模型僅僅適用于內(nèi)部網(wǎng)絡(luò)環(huán)境,因?yàn)槠渲腥狈Ρ匾姆?wù)結(jié)點(diǎn)身份驗(yàn)證,非法的消息可能會(huì)造成事務(wù)機(jī)制的崩潰。同時(shí),在這里描述的事務(wù)相對(duì)而言還是短事務(wù),而商務(wù)上對(duì)長事務(wù)的需求也是很多的。因此我們考慮了兩個(gè)方向的解決方案延伸:
安全性事務(wù)控制:所謂安全性事務(wù)控制,在我們?cè)谶@個(gè)使用SOAP消息來描述事務(wù)控制的方案中,結(jié)合SOAP消息的安全擴(kuò)展應(yīng)當(dāng)是一個(gè)比較有效的方式。Web Services Security(WS-Security)是一個(gè)SOAP Header Extension,為Web服務(wù)提供了一種保障服務(wù)安全性的語言。WS-Security通過消息完整性、消息機(jī)密性和簡單的消息認(rèn)證來實(shí)現(xiàn)消息安全的目的。這些機(jī)制能夠被用來適應(yīng)現(xiàn)有的大量的安全模型以及加密技術(shù)。WS-Security同時(shí)也提供了一個(gè)通用的機(jī)制用于將許可證(簽署了的信任聲明,如x509信任狀或者Kerberos tickets等)與消息關(guān)聯(lián),而不需要指定特殊的格式。我們可以嘗試使用這種技術(shù)來為事務(wù)控制提供安全性。
長事務(wù)支持:LRUOW(Long-running Unit of Work)模型是由IBM公司研究小組提出的一種擴(kuò)展的事務(wù)模型。這個(gè)模型允許長時(shí)間運(yùn)行的商業(yè)流程可以執(zhí)行多個(gè)事務(wù)性ACID步驟,同時(shí)保證整個(gè)處理流程的原子性和獨(dú)立性。每個(gè)LRUOW上下文創(chuàng)建一個(gè)版本空間(version space)。每個(gè)步驟都操縱版本化的對(duì)象(versioned object)。當(dāng)進(jìn)入一個(gè)LRUOW上下文時(shí),對(duì)象的最初狀態(tài)與全局的版本空間相關(guān)聯(lián)。當(dāng)一個(gè)LRUOW完成時(shí),它的版本空間與全局版本空間重新協(xié)調(diào)(reconcile)。這個(gè)擴(kuò)展的事務(wù)模型弱化了傳統(tǒng)事務(wù)特性,但提供模型應(yīng)用者更多的適用性和靈活性。為使系統(tǒng)的并發(fā)事務(wù)不因長事務(wù)而被阻塞,這個(gè)模型不強(qiáng)制長時(shí)間運(yùn)行的事務(wù)對(duì)訪問的對(duì)象加鎖,并允許因此引發(fā)的對(duì)象數(shù)據(jù)版本沖突由特定的應(yīng)用程序方法解決。這個(gè)模型也允許單個(gè)子事務(wù)的失敗不強(qiáng)制整個(gè)事務(wù)的撤消,而允許應(yīng)用程序采用補(bǔ)償事務(wù)修復(fù)失敗損失,然后讓這個(gè)事務(wù)繼續(xù)處理流程。這個(gè)模型還支持嵌套事務(wù)的提交與回滾。所以,這個(gè)擴(kuò)展的事務(wù)模型可以適應(yīng)企業(yè)內(nèi)部集成應(yīng)用程序、以及企業(yè)之間集成Web服務(wù)的需求。我們嘗試將該模型應(yīng)用到Web服務(wù)環(huán)境下去。
參考資料
- Web Service 技術(shù)/評(píng)論網(wǎng)站
- SimplePage.UDDI-China.ORG,
Web服務(wù)中文資源。
- UDDI-China.ORG,
以UDDI為主的Web服務(wù)技術(shù)網(wǎng)站。
- WebServices.ORG,
Web服務(wù)的綜合類技術(shù)網(wǎng)站。
- IBM
developerWorks/Web Service Zone, IBM的Web服務(wù)技術(shù)資源中心
- MSDN Online Web
Services Developer Resources, Microsoft的Web服務(wù)的開發(fā)者資源網(wǎng)站
- ITPapers/Web
Service, ITPapers的Web服務(wù)評(píng)論文章
- SimplePage.UDDI-China.ORG,
Web服務(wù)中文資源。
- 解決開放式應(yīng)用交互和集成的Web Services系列技術(shù)標(biāo)準(zhǔn)規(guī)范
- WS-Security規(guī)范,
Microsoft, 2001
- WS-License規(guī)范,
Microsoft, 2001
- UDDI執(zhí)行白皮書,
UDDI-China.org, UDDI.org
- UDDI技術(shù)白皮書,
UDDI-China.org, UDDI.org
- UDDI程序員API規(guī)范,
UDDI-China.org, UDDI.org
- UDDI數(shù)據(jù)結(jié)構(gòu)參考,
UDDI-China.org, UDDI.org
- Web
Service Description Language (WSDL) 1.0, IBM, 25 Sep 2000
- SOAP:
Simple Object Access Protocol Specification 1.1, IBM, Microsoft,
DevelopMentor, 2000
- XML Schema Part 0: Primer
, W3C, 2 May 2001
- Extensible Markup Language (XML) 1.0 (Second Edition), W3C, 6 Oct 2000
- WS-Security規(guī)范,
Microsoft, 2001
作者簡介
柴曉路: 上海得易電子商務(wù)技術(shù)有限公司(DealEasy)首席系統(tǒng)架構(gòu)師、XML Web Sevices技術(shù)顧問,UDDI-China.org創(chuàng)始人,UDDI Advisory Group成員,IBM developerWorks專欄作家。2000年獲復(fù)旦大學(xué)計(jì)算機(jī)科學(xué)碩士學(xué)位,曾在國際計(jì)算機(jī)科學(xué)學(xué)術(shù)會(huì)議(ICSC)、亞太區(qū)XML技術(shù)研討會(huì)(XML Asia/Pacific'99)、中國XML技術(shù)研討會(huì)(北京)、計(jì)算機(jī)科學(xué)期刊等各類國際、國內(nèi)重要會(huì)議與期刊上發(fā)表論文多篇。專長于Web Services技術(shù)架構(gòu)、基于XML的系統(tǒng)集成和數(shù)據(jù)交換應(yīng)用及方法,同時(shí)對(duì)數(shù)據(jù)庫、面向?qū)ο蠹夹g(shù)及CSCW等技術(shù)比較擅長。
- 1架構(gòu)Web Service:什么是Web服務(wù)?
- 2使用Visual Studio.Net建立web service
- 3Web Service初探
- 4石家莊OA信息化與知識(shí)價(jià)值鏈(BY AMT 夏敬華)
- 5我國商貿(mào)業(yè)將迎來新一輪的IT建設(shè)高潮
- 6ColdFusion MX增加對(duì)J2EE、XML和Web服務(wù)的兼容
- 7對(duì)某集團(tuán)公司協(xié)同辦公系統(tǒng)未來3-5年的IT規(guī)劃建設(shè)藍(lán)圖
- 8BEA向Web服務(wù)互操作發(fā)展
- 9泛普OA軟件支持在線直接發(fā)送消息、傳送文件、音頻會(huì)話等
- 10Applying .Net to Web Services
- 11第五項(xiàng)修煉簡要目錄
- 12關(guān)于模型的簡單介紹!
- 13Web服務(wù)內(nèi)幕,第10部分:深入主題:可靠性和事務(wù)
- 14IBM WebSphere以最快速度部署開放的Web服務(wù)
- 15石家莊OA信息化的基本XML和RDF技術(shù)(四):問題跟蹤程序模式
- 16源天軟件為特優(yōu)仕照明實(shí)施協(xié)同辦公管理系統(tǒng)
- 17拐點(diǎn)之年:中國管理軟件行業(yè)2008大盤點(diǎn)
- 18BEA支持JAX-RPC標(biāo)準(zhǔn)
- 19Sun拒入“WS-I” 不想跟微軟IBM玩游戲
- 202009金和協(xié)同管理“破冰之旅”助企業(yè)安然渡冬
- 21創(chuàng)造性的Intranet:Factors for Corporate Knowledge Creation
- 22架構(gòu)Web Service:描述與注冊(cè),發(fā)布Web服務(wù)
- 23Building an ASP.NET Web Service
- 24協(xié)同辦公OA軟件的常用資料和規(guī)章制度
- 25Web服務(wù)設(shè)計(jì)師,第2部分:動(dòng)態(tài)電子商務(wù)模式
- 26Web服務(wù)內(nèi)幕,第6部分:承擔(dān)責(zé)任--實(shí)現(xiàn)WSFL中的角色
- 27有一個(gè)綜合性學(xué)術(shù)資源檢索站點(diǎn),不錯(cuò)!
- 28泛普軟件如何實(shí)現(xiàn)知識(shí)庫雙機(jī)熱備
- 29Building a Distributed Web Service Using a Strongly-Typed Da
- 30BEA榮獲最佳web服務(wù)產(chǎn)品獎(jiǎng)
成都公司:成都市成華區(qū)建設(shè)南路160號(hào)1層9號(hào)
重慶公司:重慶市江北區(qū)紅旗河溝華創(chuàng)商務(wù)大廈18樓
版權(quán)所有:泛普軟件 渝ICP備14008431號(hào)-2 渝公網(wǎng)安備50011202501700號(hào) 咨詢電話:400-8352-114