當(dāng)團(tuán)隊(duì)成員完成新的工作時(shí),通過將這些更改提交到資源庫來共享他們的工作。類似地,當(dāng)他們希望獲得最新可用的工作成果時(shí),就可以根據(jù)資源庫中的更改,更新自己的本地工作空間。這意味著項(xiàng)目資源庫會(huì)因團(tuán)隊(duì)成員提交新工作成果而經(jīng)常發(fā)生更改。換句話說,資源庫應(yīng)該表示項(xiàng)目的當(dāng)前狀態(tài)。任何時(shí)候,團(tuán)隊(duì)成員都要能夠根據(jù)資源庫更新自己的工作空間,并確信它們是最新的。
維護(hù)歷史記錄也很重要,那樣就可以將當(dāng)前工作與先前版本進(jìn)行比較,如有必要,還可以回復(fù)到先前版本。協(xié)調(diào)團(tuán)隊(duì)的工作,以便只存在唯一的當(dāng)前項(xiàng)目狀態(tài)定義,以及包含團(tuán)隊(duì)已集成的工作,這些對于管理版本控制也是十分必要的。這種協(xié)調(diào)有可能是最難實(shí)現(xiàn)的目標(biāo)。
最理想的模型是:團(tuán)隊(duì)的任何成員都可以對自己有權(quán)訪問的任何資源進(jìn)行更改。因?yàn)閮蓚€(gè)團(tuán)隊(duì)成員可以提交對同一資源的更改,所以有可能發(fā)生沖突,必須解決這種沖突。這種模型假定沖突具有唯一性。但遺憾的是,沒有任何源代碼是孤立地存在的;通常它包含與其它資源隱式或顯式的相關(guān)性。源代碼引用了在其它源代碼資源中描述的構(gòu)件。但源代碼管理軟件的工作就到此為止了,因?yàn)樗⒉荒苋〈?xiàng)目管理。項(xiàng)目管理者必須履行其職責(zé):協(xié)調(diào)其它成員的工作以及負(fù)責(zé)進(jìn)度、項(xiàng)目階段和發(fā)布日期。此外,源代碼管理也不能替代開發(fā)人員之間的交流。
Eclipse 平臺如何支持代碼管理
Eclipse 平臺提供了作為團(tuán)隊(duì)在軟件項(xiàng)目中共享代碼和工作的能力。Eclipse 廣泛地支持各種代碼管理解決方案,這要?dú)w功于它的插件體系結(jié)構(gòu)(不過,現(xiàn)已推出了對 CVS 的支持)。Eclipse 平臺體系結(jié)構(gòu)的重點(diǎn)在于工作空間。工作空間維護(hù)構(gòu)建和測試軟件項(xiàng)目所需的一切。它包含對象(源代碼和資源)。它還保存了用于項(xiàng)目、IDE 和插件的配置設(shè)置。工作空間是在開發(fā)人員的機(jī)器上本地進(jìn)行維護(hù)的,而團(tuán)隊(duì)通過外部資源庫進(jìn)行協(xié)作,不同開發(fā)人員的代碼在資源庫進(jìn)行匯集。可以經(jīng)由因特網(wǎng)通過“客戶機(jī)-服務(wù)器”體系結(jié)構(gòu)訪問資源庫。
Eclipse 平臺提供了對于直接從工作空間進(jìn)行團(tuán)隊(duì)開發(fā)操作的支持。這種支持允許開發(fā)人員并發(fā)地與幾個(gè)獨(dú)立的資源庫以及不同版本的代碼或項(xiàng)目進(jìn)行交互。工作空間中的資源允許團(tuán)隊(duì)支持組件處理版本和配置管理問題。當(dāng)然,單個(gè)工作空間可以同時(shí)訪問不同類型的資源庫。Eclipse 平臺并沒有提供它自己的代碼管理解決方案;它總是依靠外部系統(tǒng)。Eclipse 平臺只對一個(gè)(但也是最流行的一個(gè))源代碼管理系統(tǒng)提供內(nèi)置支持:并發(fā)版本控制系統(tǒng)(Concurrent Versions System,CVS)。對第三方代碼管理應(yīng)用程序的支持一節(jié)中描述了使用第三方插件支持其它資源庫。
CVS 是什么?
CVS 誕生于 1986 年,當(dāng)時(shí)作為一組 shell 腳本而出現(xiàn),但它現(xiàn)在已經(jīng)發(fā)展成了最流行的針對軟件開發(fā)人員的源代碼版本管理解決方案。CVS 是用于代碼版本管理的開放源碼的客戶機(jī)/服務(wù)器解決方案,它可用于各種平臺,包括 Linux 和 Windows NT/2000/XP。請參閱本文末尾的參考資料,其中有 CVS 客戶機(jī)、服務(wù)器和源代碼的下載鏈接。
通常,CVS 的主要功能是記錄源文件的歷史。當(dāng)一組開發(fā)人員從事同一個(gè)項(xiàng)目時(shí),CVS 將他們彼此隔離開來。每個(gè)開發(fā)人員都在他/她自己的目錄中獨(dú)立工作,然后使用 CVS 資源庫(不時(shí)地)合并工作結(jié)果。
Eclipse 擁有與 Eclipse 平臺 IDE 緊密集成的內(nèi)置 CVS 客戶機(jī),它是作為一個(gè)單獨(dú)透視圖(CVS Repository Exploring 透視圖)而實(shí)現(xiàn)的,用于與 CVS 的交互。用于 CVS 的通用 Eclipse 設(shè)置(General Eclipse settings for CVS)位于 Window -> Preferences window -> Team 下。在切換到 CVS Repository Exploring 透視圖之后,就可以使用所有 CVS 操作了(轉(zhuǎn)至 Window -> Open Perspective -> Other -> CVS Repository Exploring 菜單 — 請參閱圖 1 和圖 2)。
圖 1. 切換到 CVS Repository Exploring 透視圖
首先設(shè)置資源庫的位置,它將定義用于選定 CVS 服務(wù)器/資源庫的連接參數(shù)。請確保使用 SSH 隧道(extssh
)。
圖 2. 瀏覽 CVS Repository Exploring 透視圖中的 CVS 資源庫
Eclipse/CVS 的源代碼工作流
在 CVS 團(tuán)隊(duì)協(xié)作模型中,團(tuán)隊(duì)成員彼此獨(dú)立地在他們各自的工作臺上完成自己的所有工作。最后,他們希望共享其工作。他們通過 CVS 資源庫實(shí)現(xiàn)這一點(diǎn)。CVS 使用分支(branch)模型來支持彼此獨(dú)立而又高度相互依賴的多個(gè)工作流程(course of work)。這些分支是開發(fā)團(tuán)隊(duì)用來共享和集成正在進(jìn)行中的工作的地方。可以認(rèn)為分支是一個(gè)共享的工作臺,當(dāng)團(tuán)隊(duì)成員對源代碼進(jìn)行更改時(shí)就更新這個(gè)工作臺。這個(gè)模型允許從事 CVS 團(tuán)隊(duì)項(xiàng)目的每個(gè)開發(fā)人員在進(jìn)行更改時(shí)與其他成員共享其工作,以及在項(xiàng)目進(jìn)展期間訪問其他成員的工作。
一個(gè)稱為 HEAD 的特殊分支用來表示資源庫中的主要工作流程(HEAD 通常被稱為主干)。當(dāng)團(tuán)隊(duì)成員將資源提交給該分支時(shí),會(huì)影響這些相關(guān)性。確保相關(guān)性的完整性是很重要的,因?yàn)樵摲种П硎玖水?dāng)前項(xiàng)目的狀態(tài)。當(dāng)然,任何時(shí)候,團(tuán)隊(duì)成員都可以使用該分支的內(nèi)容作為新工作的基礎(chǔ)。
那些規(guī)則不僅適用于 CVS:無論使用哪種版本控制軟件,團(tuán)隊(duì)項(xiàng)目中都有一些用于源代碼管理的常見步驟。下面是一個(gè)使用 Eclipse 內(nèi)置的 CVS 支持的示例工作流:
1. 啟動(dòng)新的團(tuán)隊(duì)項(xiàng)目
每個(gè)新的空 Eclipse 項(xiàng)目都可以通過 CVS(或受支持的任何其它源代碼管理系統(tǒng))進(jìn)行共享。開發(fā)人員也可以通過將其現(xiàn)有的代碼遷移到資源庫來共享它。要進(jìn)行共享,單擊項(xiàng)目主文件夾,在顯示的上下文菜單中使用 Team -> Share Project 選項(xiàng),如圖 3 所示。
另一個(gè)選項(xiàng)是通過從選定的 CVS 資源庫分支導(dǎo)入代碼來創(chuàng)建新的工作臺項(xiàng)目。只要選擇適當(dāng)分支(或 HEAD),然后選擇從 CVS Repository Exploring 透視圖中的上下文菜單中選擇“Checkout As Project”選項(xiàng),如圖 4 所示。
圖 4. 從現(xiàn)有的 CVS 資源庫創(chuàng)建新項(xiàng)目
2. 使用代碼并進(jìn)行更改
開發(fā)人員通過 Eclipse 工作臺在本地使用代碼,包括的工作有創(chuàng)建新資源、修改現(xiàn)有資源、編寫注釋,并在他們使用后在本地保存這些內(nèi)容。
3. 使本地更改與 CVS 資源庫同步
如果一個(gè)項(xiàng)目開發(fā)人員準(zhǔn)備提交他/她的工作,那么首先要執(zhí)行更新操作。這會(huì)針對引入的更改核對資源庫,并將這些更改添加到該開發(fā)人員的本地工作臺。這樣確保了開發(fā)人員知道這些更改可能會(huì)影響他/她將要提交的工作的完整性。使用項(xiàng)目上下文菜單中的 Compare With... 選項(xiàng)將本地版本與資源庫中存儲(chǔ)的代碼進(jìn)行比較(請參閱圖 5)。
下一步是解決最后出現(xiàn)的任何沖突,并設(shè)法再次編譯代碼。如果一切正常,那么從項(xiàng)目上下文菜單使用 Team -> Commit... 選項(xiàng)執(zhí)行提交操作,如圖 6 所示。這會(huì)使所有更改都集成到資源庫中。
4. 管理資源庫
CVS 允許開發(fā)人員將更改隔離在開發(fā)的某些獨(dú)立路徑之內(nèi),這些路徑稱為分支。當(dāng)一個(gè)開發(fā)人員更改某個(gè)分支上的文件時(shí),這種更改不會(huì)出現(xiàn)在主干或其它分支上。那些分支被命名為子版本(subversion)或代碼分叉(code fork)。稍后,由合并操作將更改從一個(gè)分支遷移到另一個(gè)分支(或主干)。然后提交這些修訂。這樣就有效地將更改復(fù)制到了另一個(gè)分支上。使用項(xiàng)目上下文菜單的 Team -> Branch... 選項(xiàng),Eclipse 使開發(fā)分支之間的遷移變得容易。
當(dāng)然,當(dāng)開發(fā)團(tuán)隊(duì)維護(hù)大型資源庫時(shí),有必要控制項(xiàng)目內(nèi)的提交和合并操作。Eclipse/CVS 集成提供了一種特殊的視圖:CVS Repository History(請參閱圖 7)。它給出了關(guān)于團(tuán)隊(duì)成員在資源庫中所執(zhí)行更改的快速預(yù)覽。
圖 7. 在 CVS Resource History 窗口中查看帶注釋的修訂歷史記錄
Eclipse 平臺提供了幾個(gè)支持代碼管理的實(shí)用程序。最有用的是補(bǔ)丁功能。它將出自兩個(gè)來源(譬如本地工作臺和資源庫)的代碼進(jìn)行比較,然后創(chuàng)建一個(gè)包含代碼差異的類似 UNIX 的補(bǔ)丁文件(請參閱圖 8)。可以將該文件發(fā)送給開發(fā)人員以將源代碼升級到最新版本。
圖 8. 創(chuàng)建用于源代碼分發(fā)的補(bǔ)丁
5. 斷開項(xiàng)目與 CVS 的連接
當(dāng)項(xiàng)目開發(fā)已經(jīng)結(jié)束,并且團(tuán)隊(duì)希望凍結(jié)源代碼時(shí),可以從 HEAD 資源庫刪除該項(xiàng)目的最終版本。斷開項(xiàng)目與 CVS 的連接將在該項(xiàng)目及其資源上禁用資源庫操作,并刪除與該項(xiàng)目相關(guān)聯(lián)的 CVS 信息(這一操作是可選的)。
可以通過項(xiàng)目上下文菜單中的 Team -> Disconnect 選項(xiàng)執(zhí)行斷開連接操作。通過選擇這個(gè)選項(xiàng),會(huì)打開 Confirm Disconnect from CVS 對話框。在將該項(xiàng)目與資源庫的連接斷開之后,該團(tuán)隊(duì)必須確定如何處理 CVS 信息。第一個(gè)選項(xiàng)是“Delete the CVS meta information”;它將禁用 CVS 團(tuán)隊(duì)菜單操作并從文件系統(tǒng)中刪除CVS 文件夾及其內(nèi)容。第二個(gè)選項(xiàng)是“Do not delete the CVS meta information”;它將禁用 CVS 團(tuán)隊(duì)菜單操作,但保留 CVS 元信息。
對第三方代碼管理應(yīng)用程序的支持
CVS 有幾個(gè)重要的限制:它不能確定單個(gè)文件或整個(gè)文件集范圍內(nèi)同時(shí)進(jìn)行的更改,它也不能檢測文件之間的邏輯沖突。其沖突概念純粹是文本意義上的,當(dāng)對于同一基本文件的兩個(gè)更改時(shí)間上非常非常接近,從而使合并命令受到干擾時(shí),就會(huì)發(fā)生沖突。CVS 也不能提供任何類似于消息傳遞這樣的交互式協(xié)作工具。幸運(yùn)的是,CVS 并不是 Eclipse 平臺所支持的唯一的源代碼管理軟件。開發(fā)人員可以通過插件擴(kuò)展 Eclipse 平臺的功能,而且目前(到 2003 年 3 月 4 日為止)已有 16 個(gè)可用于團(tuán)隊(duì)開發(fā)軟件的插件。所有插件都是由 Eclipse 社區(qū)或商業(yè)軟件供應(yīng)商創(chuàng)建的。這些插件中的大多數(shù)添加了對第三方、商業(yè)源代碼管理系統(tǒng)的支持。最有價(jià)值的插件是那些支持流行的企業(yè)代碼管理系統(tǒng)(如 Merant PVCS 和 Rational ClearCase)的插件。例如,CVS-SSH2 插件允許通過 SSH2 會(huì)話訪問 CVS,而 Microsoft Visual SourceSafe(VSS)團(tuán)隊(duì)提供程序插件添加了對 MS VSS 產(chǎn)品的支持(也可以在諸如 Linux 這樣的非 Windows 平臺上使用)。
但是,我本人所偏愛的插件是 Koi(請參閱參考資料以獲取鏈接)。盡管它并非嚴(yán)格用于源代碼控制,但這個(gè)創(chuàng)新的工具給協(xié)作開發(fā)注入了許多新的活力。其當(dāng)前版本支持工作臺到工作臺的消息傳遞、共享標(biāo)記、沖突更改通知、共享日歷和事件通知。Koi 將 XML-RPC 用作其客戶機(jī)-服務(wù)器體系結(jié)構(gòu)中的通信模型。客戶機(jī)是與“協(xié)作服務(wù)器”通信的單個(gè) Eclipse 平臺實(shí)例,而協(xié)作服務(wù)器也是一個(gè) Eclipse 插件。Koi 使用以 JDBC 訪問的關(guān)系數(shù)據(jù)庫作為數(shù)據(jù)存儲(chǔ)。可在參考資料中找到指向完整的、經(jīng)過分類的 Eclipse 插件注冊表的鏈接。
關(guān)于作者 Pawel Leszek 是 Studio B 的一位作家,他是一位專長于 Linux/Win/Mac OS 系統(tǒng)體系結(jié)構(gòu)和管理的獨(dú)立軟件顧問和作家。他具有許多操作系統(tǒng)、編程語言和網(wǎng)絡(luò)協(xié)議方面的經(jīng)驗(yàn),尤其是 Lotus Domino 和 DB2 方面。Pawel 還在 LinuxWorld 上發(fā)表過一系列文章,他是 PC World 波蘭版的 Linux 專欄作家。Pawel 和他的妻子以及可愛的小女兒住在華沙。歡迎提問并提出意見;您可以通過 pawel.leszek@ipgate.pl 與 Pawel 聯(lián)系。 |
何謂“持久層”
持久層(Persistence Layer),即專注于實(shí)現(xiàn)數(shù)據(jù)持久化應(yīng)用領(lǐng)域的某個(gè)特定系統(tǒng)的一個(gè)邏輯層面,將數(shù)據(jù)使用者和數(shù)據(jù)實(shí)體相關(guān)聯(lián)。
何謂“對象數(shù)據(jù)映射(ORM)”
ORM-Object/Relational Mapper,即“對象-關(guān)系型數(shù)據(jù)映射組件”。對于O/R,即 Object(對象)和 Relational(關(guān)系型數(shù)據(jù)),表示必須同時(shí)使用面向?qū)ο蠛完P(guān)系型數(shù)據(jù)進(jìn)行開發(fā)。
備注:建模領(lǐng)域中的 ORM 為 Object/Role Modeling(對象角色建模)。另外這里是“O/R Mapper”而非“O/R Mapping”。相對來講,O/R Mapping 描述的是一種設(shè)計(jì)思想或者實(shí)現(xiàn)機(jī)制,而 O/R Mapper指以O(shè)/R原理設(shè)計(jì)的持久化框架(Framework),包括 O/R機(jī)制還有 SQL自生成,事務(wù)處理,Cache管理等。
除了 ORM 技術(shù),還有以下幾種持久化技術(shù)
主動(dòng)域?qū)ο竽J?br />它是在實(shí)現(xiàn)中封裝了關(guān)系數(shù)據(jù)模型和數(shù)據(jù)訪問細(xì)節(jié)的一種形式。在 J2EE 架構(gòu)中,EJB 組件分為會(huì)話 EJB 和實(shí)體 EJB。會(huì)話 EJB 通常實(shí)現(xiàn)業(yè)務(wù)邏輯,而實(shí)體 EJB 表示業(yè)務(wù)實(shí)體。實(shí)體 EJB 又分為兩種:由 EJB 本身管理持久化,即 BMP(Bean-Managed Persistence);有 EJB 容器管理持久化,即 CMP(Container-Managed Persistence)。BM P就是主動(dòng)域?qū)ο竽J降囊粋€(gè)例子,BMP 表示由實(shí)體 EJB 自身管理數(shù)據(jù)訪問細(xì)節(jié)。
主動(dòng)域?qū)ο蟊旧砦挥跇I(yè)務(wù)邏輯層,因此采用主動(dòng)域?qū)ο竽J綍r(shí),整個(gè)應(yīng)用仍然是三層應(yīng)用結(jié)構(gòu),并沒有從業(yè)務(wù)邏輯層分離出獨(dú)立的持久化層。
JDO 模式
Java Data Objects(JDO)是 SUN 公司制定的描述對象持久化語義的標(biāo)準(zhǔn)API。嚴(yán)格的說,JDO 并不是對象-關(guān)系映射接口,因?yàn)樗С职褜ο蟪志没饺我庖环N存儲(chǔ)系統(tǒng)中,包括 關(guān)系數(shù)據(jù)庫、面向?qū)ο蟮臄?shù)據(jù)庫、基于 XML 的數(shù)據(jù)庫,以及其他專有存儲(chǔ)系統(tǒng)。由于關(guān)系數(shù)據(jù)庫是目前最流行的存儲(chǔ)系統(tǒng),許多 JDO 的實(shí)現(xiàn)都包含了對象-關(guān)系映射服務(wù)。
CMP 模式
在 J2EE 架構(gòu)中,CMP(Container-Managed Persistence)表示由 EJB 容器來管理實(shí)體 EJB 的持久化,EJB 容器封裝了對象-關(guān)系的映射及數(shù)據(jù)訪問細(xì)節(jié)。CMP 和 ORM 的相似之處在于,兩者都提供對象-關(guān)系映射服務(wù),都把對象持久化的任務(wù)從業(yè)務(wù)邏輯中分離出來。區(qū)別在于 CMP 負(fù)責(zé)持久化實(shí)體 EJB 組件,而 ORM 負(fù)責(zé)持久化 POJO,它是普通的基于 Java Bean 形式的實(shí)體域?qū)ο蟆?/p>
一般把基于 Java Bean 形式的實(shí)體域?qū)ο蠓Q為 POJO(Plain Old Java Object),意為又普通又古老的 Java 對象的意思。隨著各種 ORM 映射工具的日趨成熟和流行,POJO有重現(xiàn)光彩,它和基于 CMP 的實(shí)體 EJB 相比,即簡單又具有很高的可移植性,因此聯(lián)合使用 ORM 映射工具和 POJO,已經(jīng)成為一種越來越受歡迎的且用來取代 CMP 的持久化方案。POJO 的缺點(diǎn)就是無法做遠(yuǎn)程調(diào)用,不支持分布式計(jì)算。
為什么要做持久化和ORM設(shè)計(jì)
在目前的企業(yè)應(yīng)用系統(tǒng)設(shè)計(jì)中,MVC,即 Model(模型)- View(視圖)- Control(控制)為主要的系統(tǒng)架構(gòu)模式。MVC 中的 Model 包含了復(fù)雜的業(yè)務(wù)邏輯和數(shù)據(jù)邏輯,以及數(shù)據(jù)存取機(jī)制(如 JDBC的連接、SQL生成和Statement創(chuàng)建、還有ResultSet結(jié)果集的讀取等)等。將這些復(fù)雜的業(yè)務(wù)邏輯和數(shù)據(jù)邏輯分離,以將系統(tǒng)的緊耦合關(guān)系轉(zhuǎn)化為松耦合關(guān)系(即解耦合),是降低系統(tǒng)耦合度迫切要做的,也是持久化要做的工作。MVC 模式實(shí)現(xiàn)了架構(gòu)上將表現(xiàn)層(即View)和數(shù)據(jù)處理層(即Model)分離的解耦合,而持久化的設(shè)計(jì)則實(shí)現(xiàn)了數(shù)據(jù)處理層內(nèi)部的業(yè)務(wù)邏輯和數(shù)據(jù)邏輯分離的解耦合。而 ORM 作為持久化設(shè)計(jì)中的最重要也最復(fù)雜的技術(shù),也是目前業(yè)界熱點(diǎn)技術(shù)。
簡單來說,按通常的系統(tǒng)設(shè)計(jì),使用 JDBC 操作數(shù)據(jù)庫,業(yè)務(wù)處理邏輯和數(shù)據(jù)存取邏輯是混雜在一起的。
一般基本都是如下幾個(gè)步驟:
1、建立數(shù)據(jù)庫連接,獲得 Connection 對象。
2、根據(jù)用戶的輸入組裝查詢 SQL 語句。
3、根據(jù) SQL 語句建立 Statement 對象 或者 PreparedStatement 對象。
4、用 Connection 對象執(zhí)行 SQL語句,獲得結(jié)果集 ResultSet 對象。
5、然后一條一條讀取結(jié)果集 ResultSet 對象中的數(shù)據(jù)。
6、根據(jù)讀取到的數(shù)據(jù),按特定的業(yè)務(wù)邏輯進(jìn)行計(jì)算。
7、根據(jù)計(jì)算得到的結(jié)果再組裝更新 SQL 語句。
8、再使用 Connection 對象執(zhí)行更新 SQL 語句,以更新數(shù)據(jù)庫中的數(shù)據(jù)。
7、最后依次關(guān)閉各個(gè) Statement 對象和 Connection 對象。
由上可看出代碼邏輯非常復(fù)雜,這還不包括某條語句執(zhí)行失敗的處理邏輯。其中的業(yè)務(wù)處理邏輯和數(shù)據(jù)存取邏輯完全混雜在一塊。而一個(gè)完整的系統(tǒng)要包含成千上萬個(gè)這樣重復(fù)的而又混雜的處理過程,假如要對其中某些業(yè)務(wù)邏輯或者一些相關(guān)聯(lián)的業(yè)務(wù)流程做修改,要改動(dòng)的代碼量將不可想象。另一方面,假如要換數(shù)據(jù)庫產(chǎn)品或者運(yùn)行環(huán)境也可能是個(gè)不可能完成的任務(wù)。而用戶的運(yùn)行環(huán)境和要求卻千差萬別,我們不可能為每一個(gè)用戶每一種運(yùn)行環(huán)境設(shè)計(jì)一套一樣的系統(tǒng)。
所以就要將一樣的處理代碼即業(yè)務(wù)邏輯和可能不一樣的處理即數(shù)據(jù)存取邏輯分離開來,另一方面,關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)基本都是以一行行的數(shù)據(jù)進(jìn)行存取的,而程序運(yùn)行卻是一個(gè)個(gè)對象進(jìn)行處理,而目前大部分?jǐn)?shù)據(jù)庫驅(qū)動(dòng)技術(shù)(如ADO.NET、JDBC、ODBC等等)均是以行集的結(jié)果集一條條進(jìn)行處理的。所以為解決這一困難,就出現(xiàn) ORM 這一個(gè)對象和數(shù)據(jù)之間映射技術(shù)。
舉例來說,比如要完成一個(gè)購物打折促銷的程序,用 ORM 思想將如下實(shí)現(xiàn)(引自《深入淺出Hibernate》):
業(yè)務(wù)邏輯如下:
public Double calcAmount(String customerid, double amount)
{
??? // 根據(jù)客戶ID獲得客戶記錄
??? Customer customer = CustomerManager.getCustomer(custmerid);
??? // 根據(jù)客戶等級獲得打折規(guī)則
??? Promotion promotion = PromotionManager.getPromotion(customer.getLevel());
??? // 累積客戶總消費(fèi)額,并保存累計(jì)結(jié)果
??? customer.setSumAmount(customer.getSumAmount().add(amount);
??? CustomerManager.save(customer);
??? // 返回打折后的金額
??? return amount.multiply(protomtion.getRatio());
}
這樣代碼就非常清晰了,而且與數(shù)據(jù)存取邏輯完全分離。設(shè)計(jì)業(yè)務(wù)邏輯代碼的時(shí)候完全不需要考慮數(shù)據(jù)庫JDBC的那些千篇一律的操作,而將它交給 CustomerManager 和 PromotionManager 兩個(gè)類去完成。這就是一個(gè)簡單的 ORM 設(shè)計(jì),實(shí)際的 ORM 實(shí)現(xiàn)框架比這個(gè)要復(fù)雜的多。
目前有哪些流行的 ORM 產(chǎn)品
目前眾多廠商和開源社區(qū)都提供了持久層框架的實(shí)現(xiàn),常見的有
Apache OJB (http://db.apache.org/ojb/)
Cayenne (http://objectstyle.org/cayenne/)
Jaxor (http://jaxor.sourceforge.net)
Hibernate (http://www.hibernate.org)
iBatis (http://www.ibatis.com)
jRelationalFramework (http://ijf.sourceforge.net)
mirage (http://itor.cq2.org/en/oss/mirage/toon)
SMYLE (http://www.drjava.de/smyle)
TopLink (http://otn.oracle.com/products/ias/toplink/index.html)
其中 TopLink 是 Oracle 的商業(yè)產(chǎn)品,其他均為開源項(xiàng)目。
其中 Hibernate 的輕量級 ORM 模型逐步確立了在 Java ORM 架構(gòu)中領(lǐng)導(dǎo)地位,甚至取代復(fù)雜而又繁瑣的 EJB 模型而成為事實(shí)上的 Java ORM 工業(yè)標(biāo)準(zhǔn)。而且其中的許多設(shè)計(jì)均被 J2EE 標(biāo)準(zhǔn)組織吸納而成為最新 EJB 3.0 規(guī)范的標(biāo)準(zhǔn),這也是開源項(xiàng)目影響工業(yè)領(lǐng)域標(biāo)準(zhǔn)的有力見證。
參考文獻(xiàn):1、《深入淺出Hibernate》
???????? 2、《精通Hibernate:Java對象持久化技術(shù)詳解》
內(nèi)容摘要:
CVS是一個(gè)C/S系統(tǒng),多個(gè)開發(fā)人員通過一個(gè)中心版本控制系統(tǒng)來記錄文件版本,從而達(dá)到保證
文件同步的目的。工作模式如下:
CVS服務(wù)器(文件版本庫)
/ | \
(版 本 同 步)
/ | \
開發(fā)者1 開發(fā)者2 開發(fā)者3
作為一般開發(fā)人員挑選2,6看就可以了,CVS的管理員則更需要懂的更多一些,最后還簡單介紹了
一些Windows下的cvs客戶端使用,CVS遠(yuǎn)程用戶認(rèn)證的選擇及與BUG跟蹤系統(tǒng)等開發(fā)環(huán)境的集成
問題。
一個(gè)系統(tǒng)20%的功能往往能夠滿足80%的需求,CVS也不例外,以下是CVS最常用的功能,可能還不
到它全部命令選項(xiàng)的20%,作為一般開發(fā)人員平時(shí)會(huì)用cvs update和cvs commit就夠了,更多的需求在
實(shí)際應(yīng)用過程中自然會(huì)出現(xiàn),不時(shí)回頭看看相關(guān)文檔經(jīng)常有意外的收獲。
tcsh
setenv CVSROOT /path/to/cvsroot
bash
CVSROOT=/path/to/cvsroot ; export CVSROOT
后面還提到遠(yuǎn)程CVS服務(wù)器的設(shè)置:
CVSROOT=:ext:$USER@test.server.address#port:/path/to/cvsroot CVS_RSH=ssh;
export CVSROOT CVS_RSH
初始化:CVS版本庫的初始化。
cvs init
一個(gè)項(xiàng)目的首次導(dǎo)入
cvs import -m "write some comments here" project_name vendor_tag release_tag
執(zhí)行后:會(huì)將所有源文件及目錄導(dǎo)入到/path/to/cvsroot/project_name目錄下
vender_tag: 開發(fā)商標(biāo)記
release_tag: 版本發(fā)布標(biāo)記
項(xiàng)目導(dǎo)出:將代碼從CVS庫里導(dǎo)出
cvs checkout project_name
cvs 將創(chuàng)建project_name目錄,并將最新版本的源代碼導(dǎo)出到相應(yīng)目錄中。這個(gè)checkout和Virvual SourceSafe中的check out不是一個(gè)概念,相對于Virvual SourceSafe的check out是cvs update,
check in是cvs commit。
注意:第一次導(dǎo)出以后,就不是通過cvs checkout來同步文件了,而是要進(jìn)入剛才cvs checkout
project_name導(dǎo)出的project_name目錄下進(jìn)行具體文件的版本同步(添加,修改,刪除)操作。
將文件同步到最新的版本
cvs update
不制定文件名,cvs將同步所有子目錄下的文件,也可以制定某個(gè)文件名/目錄進(jìn)行同步
cvs update file_name
最好每天開始工作前或?qū)⒆约旱墓ぷ鲗?dǎo)入到CVS庫里前都要做一次,并養(yǎng)成“先同步 后修改”的習(xí)
慣,和Virvual SourceSafe不同,CVS里沒有文件鎖定的概念,所有的沖突是在commit之前解決,如果
你修改過程中,有其他人修改并commit到了CVS 庫中,CVS會(huì)通知你文件沖突,并自動(dòng)將沖突部分用
>>>>>>
content on cvs server
<<<<<<
content in your file
>>>>>>
標(biāo)記出來,由你確認(rèn)沖突內(nèi)容的取舍。
版本沖突一般是在多個(gè)人修改一個(gè)文件造成的,但這種項(xiàng)目管理上的問題不應(yīng)該指望由CVS來解決。
確認(rèn)修改寫入到CVS庫里
cvs commit -m "write some comments here" file_name
注意:CVS的很多動(dòng)作都是通過cvs commit進(jìn)行最后確認(rèn)并修改的,最好每次只修改一個(gè)文件。在確認(rèn)
的前,還需要用戶填寫修改注釋,以幫助其他開發(fā)人員了解修改的原因。如果不用寫-m "comments"而
直接確認(rèn)`cvs commit file_name` 的話,cvs會(huì)自動(dòng)調(diào)用系統(tǒng)缺省的文字編輯器(一般是vi)要求你寫入注釋。
注釋的質(zhì)量很重要:所以不僅必須要寫,而且必須寫一些比較有意義的內(nèi)容:以方便其他開發(fā)人員能
夠很好的理解不好的注釋,很難讓其他的開發(fā)人員快速的理解:比如: -m "bug fixed" 甚至 -m ""
好的注釋,甚至可以用中文: -m "在用戶注冊過程中加入了Email地址校驗(yàn)"
修改某個(gè)版本注釋:每次只確認(rèn)一個(gè)文件到CVS庫里是一個(gè)很好的習(xí)慣,但難免有時(shí)候忘了指定文件
名,把多個(gè)文件以同樣注釋commit到CVS庫里了,以下命令可以允許你修改某個(gè)文件某個(gè)版本的注釋:
cvs admin -m 1.3:"write some comments here" file_name
添加文件
創(chuàng)建好新文件后,比如:touch new_file
cvs add new_file
注意:對于圖片,Word文檔等非純文本的項(xiàng)目,需要使用cvs add -kb選項(xiàng)按2進(jìn)制文件方式導(dǎo)入(k表示
擴(kuò)展選項(xiàng),b表示binary),否則有可能出現(xiàn)文件被破壞的情況
比如:
cvs add -kb new_file.gif
cvs add -kb readme.doc
如果關(guān)鍵詞替換屬性在首次導(dǎo)入時(shí)設(shè)置錯(cuò)了怎么辦?
cvs admin -kkv new_file.css
然后確認(rèn)修改并注釋
cvs ci -m "write some comments here"
刪除文件
將某個(gè)源文件物理刪除后,比如:rm file_name
cvs rm file_name
然后確認(rèn)修改并注釋
cvs ci -m "write some comments here"
以上面前2步合并的方法為:
cvs rm -f file_name
cvs ci -m "why delete file"
注意:很多cvs命令都有縮寫形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;
添加目錄
cvs add dir_name
查看修改歷史
cvs log file_name
cvs history file_name
查看當(dāng)前文件不同版本的區(qū)別
cvs diff -r1.3 -r1.5 file_name
查看當(dāng)前文件(可能已經(jīng)修改了)和庫中相應(yīng)文件的區(qū)別
cvs diff file_name
cvs的web界面提供了更方便的定位文件修改和比較版本區(qū)別的方法,具體安裝設(shè)置請看后面的cvsweb
使用
正確的通過CVS恢復(fù)舊版本的方法:
如果用cvs update -r1.2 file.name
這個(gè)命令是給file.name加一個(gè)STICK TAG: "1.2" ,雖然你的本意只是想將它恢復(fù)到1.2版本
正確的恢復(fù)版本的方法是:cvs update -p -r1.2 file_name >file_name
如果不小心已經(jīng)加成STICK TAG的話:用cvs update -A 解決
移動(dòng)文件/文件重命名
cvs里沒有cvs move或cvs rename,因?yàn)檫@兩個(gè)操作是可以由先cvs remove old_file_name,然后cvs add new_file_name實(shí)現(xiàn)的。
刪除/移動(dòng)目錄
最方便的方法是讓管理員直接移動(dòng),刪除CVSROOT里相應(yīng)目錄(因?yàn)镃VS一個(gè)項(xiàng)目下的子目錄都是
獨(dú)立的,移動(dòng)到$CVSROOT目錄下都可以作為新的獨(dú)立項(xiàng)目:好比一顆樹,其實(shí)砍下任意一枝都能獨(dú)
立存活),對目錄進(jìn)行了修改后,要求其開發(fā)人員重新導(dǎo)出項(xiàng)目cvs checkout project_name 或者用
cvs update -dP同步。
項(xiàng)目發(fā)布導(dǎo)出不帶CVS目錄的源文件
做開發(fā)的時(shí)候你可能注意到了,每個(gè)開發(fā)目錄下,CVS都創(chuàng)建了一個(gè)CVS/目錄。里面有文件用于記錄
當(dāng)前目錄和CVS庫之間的對應(yīng)信息。但項(xiàng)目發(fā)布的時(shí)候你一般不希望把文件目錄還帶著含有CVS信息
的CVS目錄吧,這個(gè)一次性的導(dǎo)出過程使用cvs export命令,不過export只能針對一個(gè)TAG或者日期導(dǎo)出,比如:
cvs export -r release1 project_name
cvs export -D 20021023 project_name
cvs export -D now project_name
cvs tag release_1_0
開始一個(gè)新的里程碑:
cvs commit -r 2 標(biāo)記所有文件開始進(jìn)入2.x的開發(fā)
注意:CVS里的revsion和軟件包的發(fā)布版本可以沒有直接的關(guān)系。但所有文件使用和發(fā)布版本一致的
版本號比較有助于維護(hù)。
版本分支的建立
在開發(fā)項(xiàng)目的2.x版本的時(shí)候發(fā)現(xiàn)1.x有問題,但2.x又不敢用,則從先前標(biāo)記的里程碑:release_1_0導(dǎo)出
一個(gè)分支 release_1_0_patch
cvs rtag -b -r release_1_0 release_1_0_patch proj_dir
一些人先在另外一個(gè)目錄下導(dǎo)出release_1_0_patch這個(gè)分支:解決1.0中的緊急問題,
cvs checkout -r release_1_0_patch
而其他人員仍舊在項(xiàng)目的主干分支2.x上開發(fā)
在release_1_0_patch上修正錯(cuò)誤后,標(biāo)記一個(gè)1.0的錯(cuò)誤修正版本號
cvs tag release_1_0_patch_1
如果2.0認(rèn)為這些錯(cuò)誤修改在2.0里也需要,也可以在2.0的開發(fā)目錄下合并release_1_0_patch_1中的修改到
當(dāng)前代碼中:
cvs update -j release_1_0_patch_1
常見的登陸格式如下:
cvs -d :pserver:cvs_user_name@cvs.server.address:/path/to/cvsroot login
例子:
cvs -d :pserver:cvs@samba.org:/cvsroot login
不是很安全,因此一般是作為匿名只讀CVS訪問的方式。從安全考慮,通過系統(tǒng)本地帳號認(rèn)證并通過
SSH傳輸是比較好的辦法,通過在客戶機(jī)的 /etc/profile里設(shè)置一下內(nèi)容:
CVSROOT=:ext:$USER@cvs.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH
所有客戶機(jī)所有本地用戶都可以映射到CVS服務(wù)器相應(yīng)同名帳號了。
比如:
CVS服務(wù)器是192.168.0.3,上面CVSROOT路徑是/home/cvsroot,另外一臺開發(fā)客戶機(jī)是192.168.0.4,
如果 tom在2臺機(jī)器上都有同名的帳號,那么從192.168.0.4上設(shè)置了:
export CVSROOT=:ext:tom@192.168.0.3:/home/cvsroot
export CVS_RSH=ssh
tom就可以直接在192.168.0.4上對192.168.0.3的cvsroot進(jìn)行訪問了(如果有權(quán)限的話)
cvs checkout project_name
cd project_name
cvs update
...
cvs commit
如果CVS所在服務(wù)器的SSH端口不在缺省的22,或者和客戶端與CVS服務(wù)器端SSH缺省端口不一致,
有時(shí)候設(shè)置了:
:ext:$USER@test.server.address#port:/path/to/cvsroot
仍然不行,比如有以下錯(cuò)誤信息:
ssh: test.server.address#port: Name or service not known
cvs [checkout aborted]: end of file from server (consult above messages if any)
解決的方法是做一個(gè)腳本指定端口轉(zhuǎn)向(不能使用alias,會(huì)出找不到文件錯(cuò)誤):
創(chuàng)建一個(gè)/usr/bin/ssh_cvs文件,假設(shè)遠(yuǎn)程服務(wù)器的SSH端口是非缺省端口:34567
#!/bin/sh
/usr/bin/ssh -p 34567 "$@"
然后:chmod +x /usr/bin/ssh_cvs
并CVS_RSH=ssh_cvs; export CVS_RSH
注意:port是指相應(yīng)服務(wù)器SSH的端口,不是指cvs專用的pserver的端口
使用的樣例可以看:http://www.freebsd.org/cgi/cvsweb.cgi
CVSWEB的下載:CVSWEB從最初的版本已經(jīng)演化出很多功能界面更豐富的版本,這個(gè)是我個(gè)人感
覺安裝設(shè)置比較方便的:
原先在:http://www.spaghetti-code.de/software/linux/cvsweb/,但目前已經(jīng)刪除,目前仍可以在本站下載CVSWEB,其實(shí)最近2年FreeBSD的CVSWeb項(xiàng)目已經(jīng)有了更好的發(fā)展吧,而當(dāng)初沒有用FreeBSD那個(gè)
版本主要就是因?yàn)闆]有彩色的文件Diff功能。
下載解包:
tar zxf cvsweb.tgz
把配置文件cvsweb.conf放到安全的地方(比如和apache的配置放在同一個(gè)目錄下),
修改:cvsweb.cgi讓CGI找到配置文件:
$config = $ENV{'CVSWEB_CONFIG'} || '/path/to/apache/conf/cvsweb.conf';
轉(zhuǎn)到/path/to/apache/conf下并修改cvsweb.conf:
CVSWEB可不能隨便開放給所有用戶,因此需要使用WEB用戶認(rèn)證:
先生成 passwd:
/path/to/apache/bin/htpasswd -c cvsweb.passwd user
修改httpd.conf: 增加
<Directory "/path/to/apache/cgi-bin/cvsweb/">
AuthName "CVS Authorization"
AuthType Basic
AuthUserFile /path/to/cvsweb.passwd
require valid-user
</Directory>
幾個(gè)常用的缺省文件:
default.php
<?php
/*
* Copyright (c) 2002 Company Name.
* $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11
chedong Exp $
*/
?>
====================================
Default.java: 注意文件頭一般注釋用 /* 開始 JAVADOC注釋用 /** 開始的區(qū)別
/*
* Copyright (c) 2002 MyCompany Name.
* $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11
chedong Exp $
*/
package com.mycompany;
import java.;
/**
* comments here
*/
public class Default {
/**
* Comments here
* @param
* @return
*/
public toString() {
}
}
====================================
default.pl:
#!/usr/bin/perl -w
# Copyright (c) 2002 Company Name.
# $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11
chedong Exp $
# file comments here
use strict;
CVS沒有文件鎖定模式,VSS在check out同時(shí),同時(shí)記錄了文件被導(dǎo)出者鎖定。
CVS的update和commit, VSS是get_lastest_version和check in
對應(yīng)VSS的check out/undo check out的CVS里是edit和unedit
在CVS中,標(biāo)記自動(dòng)更新功能缺省是打開的,這樣也帶來一個(gè)潛在的問題,就是不用-kb方式添加
binary文件的話在cvs自動(dòng)更新時(shí)可能會(huì)導(dǎo)致文件失效。
$Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $ $Date: 2003/11/09
07:57:11 $這樣的標(biāo)記在Virsual SourceSafe中稱之為Keyword Explaination,缺省是關(guān)閉
的,需要通過OPITION打開,并指定需要進(jìn)行源文件關(guān)鍵詞掃描的文件類型:*.txt,*.java, *.html...
對于Virsual SourceSafe和CVS都通用的TAG有:
$Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $
$Author: chedong $
$Date: 2003/11/09 07:57:11 $
$Revision: 1.9 $
我建議盡量使用通用的關(guān)鍵詞保證代碼在CVS和VSS都能方便的跟蹤。
cvs Windows客戶端:目前穩(wěn)定版本為1.2
http://cvsgui.sourceforge.net
ssh Windows客戶端
http://www.networksimplicity.com/openssh/
安裝好以上2個(gè)軟件以后:
WinCVS客戶端的admin==>preference設(shè)置
1 在general選單里
設(shè)置CVSROOT: username@192.168.0.123:/home/cvsroot
設(shè)置Authorization: 選擇SSH server
2 Port選單里
鉤上:check for alternate rsh name
并設(shè)置ssh.exe的路徑,缺省是裝在 C:\Program Files\NetworkSimplicity\ssh\ssh.exe
然后就可以使用WinCVS進(jìn)行cvs操作了,所有操作都會(huì)跳出命令行窗口要求你輸入服務(wù)器端的認(rèn)
證密碼。
當(dāng)然,如果你覺得這樣很煩的話,還有一個(gè)辦法就是生成一個(gè)沒有密碼的公鑰/私鑰對,并設(shè)置
CVS使用基于公鑰/私鑰的SSH認(rèn)證(在general 選單里)。
可以選擇的diff工具:examdiff
下載:
http://www.prestosoft.com/examdiff/examdiff.htm
還是在WinCVS菜單admin==>preference的WinCVS選單里
選上:Externel diff program
并設(shè)置diff工具的路徑,比如:C:\Program Files\ed16i\ExamDiff.exe
在對文件進(jìn)行版本diff時(shí),第一次需要將窗口右下角的use externel diff選上。
這里首先說一下CVS的pserver模式下的用戶認(rèn)證,CVS的用戶認(rèn)證服務(wù)是基于inetd中的:
cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver
一般在2401端口(這個(gè)端口號很好記:49的平方)
CVS用戶數(shù)據(jù)庫是基于CVSROOT/passwd文件,文件格式:
[username]:[crypt_password]:[mapping_system_user]
由于密碼都用的是UNIX標(biāo)準(zhǔn)的CRYPT加密,這個(gè)passwd文件的格式基本上是apache的htpasswd格式
的擴(kuò)展(比APACHE的 PASSWD文件多一個(gè)系統(tǒng)用戶映射字段),所以這個(gè)文件最簡單的方法可
以用
apache/bin/htpasswd -b myname mypassword
創(chuàng)建。注意:通過htpasswd創(chuàng)建出來的文件會(huì)沒有映射系統(tǒng)用戶的字段
例如:
new:geBvosup/zKl2
setup:aISQuNAAoY3qw
test:hwEpz/BX.rEDU
映射系統(tǒng)用戶的目的在于:你可以創(chuàng)建一個(gè)專門的CVS服務(wù)帳號,比如用apache的運(yùn)行用戶apache,
并將/home/cvsroot目錄下的所有權(quán)限賦予這個(gè)用戶,然后在passwd文件里創(chuàng)建不同的開發(fā)用戶帳號,
但開發(fā)用戶帳號最后的文件讀寫權(quán)限都映射為apache用戶,在SSH模式下多個(gè)系統(tǒng)開發(fā)用戶需要在
同一個(gè)組中才可以相互讀寫CVS庫中的文件。
進(jìn)一步的,你可以將用戶分別映射到apache這個(gè)系統(tǒng)用戶上。
new:geBvosup/zKl2:apache
setup:aISQuNAAoY3qw:apache
test:hwEpz/BX.rEDU:apache
CVSTrac很好的解決了CVSROOT/passwd的管理問題,而且包含了BUG跟蹤報(bào)告系統(tǒng)和集成WIKI交
流
功能等,使用的 CGI方式的安裝,并且基于GNU Public License:
在inetd里加入cvspserver服務(wù):
cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver
xietd的配置文件:%cat cvspserver
service cvspserver
{
disable = no
socket_type = stream
wait = no
user = apache
server = /usr/bin/cvs
server_args = -f --allow-root=/home/cvsroot pserver
log_on_failure += USERID
}
注意:這里的用戶設(shè)置成apache目的是和/home/cvsroot的所有用戶一致,并且必須讓這個(gè)這個(gè)用戶對/home/cvsroot/下的 CVSROOT/passwd和cvstrac初始化生成的myproj.db有讀取權(quán)限。
安裝過程
修改登錄密碼,進(jìn)行BUG報(bào)告等,
更多使用細(xì)節(jié)可以在使用中慢慢了解。
對于前面提到的WinCVS在perference里設(shè)置:
CVSROOT欄輸入:username@ip.address.of.cvs:/home/cvsroot
Authenitication選擇:use passwd file on server side
就可以了從服務(wù)器上進(jìn)行CVS操作了。
CVS的權(quán)限管理分2種策略:
Linux上通過ssh連接CVS服務(wù)器的多個(gè)開發(fā)人員:通過都屬于apache組實(shí)現(xiàn)文件的共享讀寫開發(fā)人員
有開發(fā)服務(wù)器上的系統(tǒng)帳號:sysuser1 sysuser2,設(shè)置讓他們都屬于apache組,因?yàn)橥ㄟ^cvs新導(dǎo)入的
項(xiàng)目都是對組開放的:664權(quán)限的,這樣無論那個(gè)系統(tǒng)用戶導(dǎo)入的項(xiàng)目文件,只要文件的組宿主是apache,所有其他同組系統(tǒng)開發(fā)用戶就都可以讀寫;基于ssh遠(yuǎn)程認(rèn)證的也是一樣。
? ?apache(system group)
/ ? ? ? ? ? ?| ? ? ? ? ? \
sysuser1 ? sysuser2 ? ? sysuser3
Windows上通過cvspserver連接CVS服務(wù)器的多個(gè)開發(fā)人員:通過在passwd文件種映射成 apache用戶
實(shí)現(xiàn)文件的共享讀寫
他們的帳號通過CVSROOT/passwd和readers writers這幾個(gè)文件管理;通過cvstrac設(shè)置所有
虛擬用戶都映射到apache用戶上即可。
? ?apache(system user)
/ ? ? ? ? ? ?| ? ? ? ? ? ?\
windev1 ? ? windev2 ? ? ?windev3? ? ? ? ? ? ?
利用CVS WinCVS/CVSWeb/CVSTrac 構(gòu)成了一個(gè)相對完善的跨平臺工作組開發(fā)版本控制環(huán)境。
相關(guān)資源:
CVS HOME:
http://www.cvshome.org
CVS FAQ:
http://www.loria.fr/~molli/cvs-index.html
相關(guān)網(wǎng)站:
http://directory.google.com/Top/Computers/Software/Configuration_Management/Tools/Concurrent_
Versions_System/
CVS--并行版本系統(tǒng)
http://www.soforge.com/cvsdoc/zh_CN/book1.html
CVS 免費(fèi)書:
http://cvsbook.red-bean.com/
CVS命令的速查卡片 refcards.com/refcards/cvs/
WinCVS:
http://cvsgui.sourceforge.net/
CVSTrac: A Web-Based Bug And Patch-Set Tracking System For CVS
http://www.cvstrac.org
StatCVS:基于CVS的代碼統(tǒng)計(jì)工具:按代碼量,按開發(fā)者的統(tǒng)計(jì)表等
http://sourceforge.net/projects/statcvs
首先,由于其他所有的GUI工具都是基于CVS基本協(xié)議的,而且他們可能會(huì)提供CVS的命令行或者等價(jià)形
式作為顯示的一部分,所以你應(yīng)該對命令行操作有所了解。如果你還沒有一個(gè)cvs。exe的命令行程序,從
www.cvsnt.org你可以得到一個(gè)cvsnt的下載連接,其中就包含了一個(gè)命令行的cvs.exe程序。我們先從它開始
(為了作為一個(gè)client使用,你不需要安裝cvsnt的server組件)。CVSNT的cvs.exe是專門為windows編寫的,你
需要把cvs.exe放在你的path里面。
1.進(jìn)入命令行方式。和VSS一樣,你也需要在本地有一個(gè)工作目錄對應(yīng)于一個(gè)repository。假設(shè)這個(gè)目錄是'd:\works\sandbox'。
請切換到這個(gè)目錄。輸入"cvs"。你會(huì)看到:
這些提示信息告訴您關(guān)于cvs的基本語法。cvs后面跟著的是全局參數(shù),然后是命令,最后是命令的參數(shù)。2.login
正確的login不會(huì)有任何輸出,否則會(huì)告訴你錯(cuò)誤原因。
如果login失敗,則可以先嘗試命令:set cvsroot=:pserver:cao@IP或者計(jì)算機(jī)名字/CVSRoot
3.下面我們看看這個(gè)CVS server中有哪些module。
4.假設(shè)現(xiàn)在我們工作的項(xiàng)目是projectX,下面我們需要得到它下面的全部文件。
現(xiàn)在讓我們看一下我們得到了什么。
在d:/works/sandbox目錄下,你可以看到有一個(gè)projectX目錄。這就是你得到的所有文件。
這個(gè)目錄下你會(huì)發(fā)現(xiàn)一個(gè)叫做 CVS的目錄。危險(xiǎn)!請不要?jiǎng)h除這個(gè)目錄,或者改名,或者改動(dòng)其中的
任何文件,除非你知道你在做什么。這個(gè)目錄是CVS的控制目錄。如果你用過source safe,你一定很熟悉。scc這個(gè)文件,CVS目錄的作用就和這個(gè)控制文件一樣,都是用來記錄你訪問服務(wù)器的參數(shù)。
這里我們需要解釋一下cvs和VSS的名詞差別。在VSS中,checkout意味著你將獲得一個(gè)文件的修改權(quán),而
cvs中checkout的這個(gè)含義取消了,僅僅指取得文件的新版本。很多cvs server會(huì)有一個(gè)anonymous用戶,他
只有checkout權(quán)限,也就意味著它只讀。???
5.讓我們試著加入一個(gè)文件:
在d:/works/sandbox/projectX下,新建一個(gè)文件newfile.txt,
然后,在這個(gè)目錄下執(zhí)行:
你需要commit它才能被sever接受。
一個(gè)notepad窗口彈出請您輸入注釋。
這是commit完成的結(jié)果。現(xiàn)在的版本號是1.1。
6.好了,現(xiàn)在假設(shè)您需要改一下這個(gè)文件的內(nèi)容。
CVS可以幫助您比較現(xiàn)在您的版本和repository中的版本有什么不同。
好了,現(xiàn)在您可以提交您的新文件。
CVS會(huì)幫您保留您的各個(gè)版本。在commit之后,現(xiàn)在我們來看一看各個(gè)版本的history。
7.最后,為了完成這個(gè)試驗(yàn),請把這個(gè)newfile文件刪去。
我們現(xiàn)在認(rèn)識了一些最基本的CVS入門級指令。
其實(shí)CVS是非常強(qiáng)大的,我們并沒有用到一些更復(fù)雜的功能,請參閱cvs的手冊來得到更為詳盡的幫助。
轉(zhuǎn)載至:http://www.redsaga.com/CVS_newbie_win32/
5、打開一個(gè)cmd窗口,輸入命令set cvsroot=:pserver:sunxdd@server/Root(sunxdd是剛才建立的用戶名,server是安裝的計(jì)算機(jī)名稱或者IP,/Root是剛才建立的文件夾別名,每次登陸之前都要這樣告訴系統(tǒng)建立這樣一個(gè)環(huán)境變量)
cvs login
密碼為空
這時(shí)會(huì)登錄成功
改密碼
cvs passwd
到這里CVSNT服務(wù)器基本上搞定了。
有用的資源:
http://edu.tmn.cn/html/5/47/185/2005210/104247.htm
http://www.redsaga.com/CVS_newbie_win32/#tortoisecvs
http://sunxdd.blogchina.com/2338489.html
加入WAP書簽
<?xml version="1.0"?> <!DOCTYPE CHARACTERISTIC-LIST SYSTEM "/DTD/characteristic_list.xml"> <CHARACTERISTIC-LIST> <CHARACTERISTIC TYPE="ADDRESS"> <PARM NAME="BEARER" VALUE="GPRS"/> <PARM NAME="PROXY" VALUE="10.0.0.172"/> <PARM NAME="PORT" VALUE="9201"/> <PARM NAME="GPRS_ACCESSPOINTNAME" VALUE="wap.02826.com"/> <PARM NAME="PPP_AUTHTYPE" VALUE="PAP"/> </CHARACTERISTIC> <CHARACTERISTIC TYPE="NAME"> <PARM NAME="NAME" VALUE="wmzsoft GPRS"/> </CHARACTERISTIC> <CHARACTERISTIC TYPE="BOOKMARK"/> <PARM NAME="NAME" VALUE="02826"/> <PARM NAME="URL" VALUE=" http://wap.02826.com "/> </CHARACTERISTIC> </CHARACTERISTIC-LIST> |
<body>
<?php
$title=$_POST["title"];
$text=$_POST["text"];
$name=$_POST["name"];
$count=$_POST["i"];
include_once("數(shù)據(jù)庫連接文件");
if (empty($title)||empty($text)||empty($bar_name)){
?echo "標(biāo)題或內(nèi)容不能空
?die("<br /><a href=\"index.php\">重新來過</a>");
}
/*這里是數(shù)據(jù)查詢語言取出要用的數(shù)據(jù)*/
if(in_array("0", $_FILES['userfile']['error'])){//上傳文件開始
?$uploaddir= 'attfile/';//設(shè)置上傳的文件夾地址
?$FILES_EXT=array('.gif','.jpg','.mp3','.3gp');//設(shè)置允許上傳文件的類型
?$MAX_SIZE = 20000000;//設(shè)置文件上傳限制20000000byte=2M
?for ($i=0;$i<$count;$i++){
??$FILES_NAME=$_FILES['userfile']['name'][$i];//客戶端文件名
??//取出文件后綴名,strrpos()從標(biāo)記開始前字節(jié)個(gè)數(shù)(不算標(biāo)記),substr()顯示從第strrpos()之后的字符
??$file_ext=substr($FILES_NAME,strrpos($FILES_NAME,"."));
??//檢查文件大小
??if($_FILES['userfile']['size'][$i]>$MAX_SIZE){
???echo "文件大小超程序允許范圍!";
???exit;
??}
??//檢查文件類型
??if(in_array($file_ext, $FILES_EXT)){
???$_FILES['userfile']['name'][$i]=date("YmdHis").rand(10000,1000000).$file_ext;
???//echo $_FILES['userfile']['name'][$i];
???$uploadfile = $uploaddir.$_FILES['userfile']['name'][$i];//上傳后文件的路徑及文件名
???//echo $uploadfile;
???//用move函數(shù)生成臨時(shí)文件名,并按照 $_FILES['userfile']['name']上傳到$uploaddir下
???if (move_uploaded_file($_FILES['userfile']['tmp_name'][$i], $uploadfile)) {
????//將上傳后的路徑寫入到數(shù)據(jù)庫中
????$post_id=(int)$post_id;
????$uploadfile="attfile/".$_FILES['userfile']['name'][$i];
????$sql=插入語句
????$stmt=$db->prepare($sql);
????$stmt->execute();
????print "<br />文件\n{$FILES_NAME}\n上傳成功!";
???} else {
????print "上傳錯(cuò)誤!? 以下是上傳的信息:\n";
????print_r($_FILES);
???}
??}
??else{
???echo "{$FILES_NAME}\n不是允許上傳的文件類型!";
???exit;
??}
?}
}
?>
</body>
</html>
Echo?? "上傳文件大小:";
echo $_FILES['userfile']['size'];
//已上傳文件的大小,單位為字節(jié)。
echo "<br>";
Echo?? "文件上傳后被臨時(shí)儲(chǔ)存為:";
echo $_FILES['userfile']['tmp_name'];
//文件被上傳后在服務(wù)端儲(chǔ)存的臨時(shí)文件名。
echo "<br>";
$Erroe=$_FILES['userfile']['error'];
switch($Erroe){
?case 0:
?Echo?? "上傳成功"; break;
?case 1:
?Echo?? "上傳的文件超過了 php.ini 中 upload_max_filesize 選項(xiàng)限制的值."; break;
?case 2:
?Echo?? "上傳文件的大小超過了 HTML 表單中 MAX_FILE_SIZE 選項(xiàng)指定的值。";?? break;
?case 3:
?Echo?? "文件只有部分被上傳";break;
?case 4:
?Echo?? "沒有文件被上傳";break;
}
?>
(2)<?php
$uploaddir= '../attfile/';//設(shè)置上傳的文件夾地址
$FILES_EXT=array('.gif','.jpg','.bmp');//設(shè)置允許上傳文件的類型
$MAX_SIZE = 20000000;//設(shè)置文件上傳限制20000000byte=2M
for ($i=0;$i<count($userfile);$i++){
?$FILES_NAME=$_FILES['userfile']['name'][$i];//客戶端文件名
}
//echo $FILES_NAME;
//取出文件后綴名,strrpos()從標(biāo)記開始前字節(jié)個(gè)數(shù)(不算標(biāo)記),substr()顯示從第strrpos()之后的字符
$file_ext=substr($FILES_NAME,strrpos($FILES_NAME,"."));
//echo $file_ext;
//檢查文件大小
if($_FILES['userfile']['size']>$MAX_SIZE){
?echo "文件大小超程序允許范圍!";
?exit;
}
//檢查文件類型
if(in_array($file_ext, $FILES_EXT)){
?$_FILES['userfile']['name']=date("YmdHis").rand().$file_ext;
?$uploadfile = $uploaddir.$_FILES['userfile']['name'];//上傳后文件的路徑及文件名
?//將上傳后的路徑寫入到數(shù)據(jù)庫中
?//用move函數(shù)生成臨時(shí)文件名,并按照 $_FILES['userfile']['name']上傳到$uploaddir下
?if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
??print "\n上傳成功!";
?} else {
??print "上傳錯(cuò)誤!? 以下是上傳的信息:\n";
??print_r($_FILES);
?}
}
else{
?echo "{$file_ext}不是允許上傳的文件類型!";
?exit;
}
?>
小技巧>>1、當(dāng)在提交時(shí),希望確認(rèn)是否要提交可以在<form>里如這樣加入:<form onsubmit="return confirm('你真的要提交嗎?')">
2、在php里希望返回時(shí)所有在文本框里的東西都保留可以這樣:<a href=javascript:history.back(1)>重新來過</a>。