qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          論如何進行有效的需求管理

           論文摘要:
            本文主要討論如何更有效的進行需求管理,需求管理中需求考慮的一些問題,項目中事先識別的風險和沒有預料到而發生的變更等風險的應對措施的分析,也包括項目中發生的變更和項目中發生問題的分析統計,以及需求管理中的一些應對措施。
            關鍵字:
            需求管理, 業務建模、項目管理、數據流圖
            通過高級項目經理5天課程的培訓,個人感覺對于原先的工作實踐有了一個很好的指導,從原先的實踐上升了一個層次,對于實踐有了一個很好的理論指導。
            我想很多人可能會與我同感,一個項目做了很久,感覺總是做不完,就像一個“無底洞”。你想加人盡快完成這個項目,而用戶總是有新的需求要項目開發方來做,就像用戶是一個不知廉恥的要求者,而開發方是在苦苦接收的接受者。實際上,這里涉及到一個需求管理的概念。項目中哪些該做,哪些不該做,做到什么程度,都是由需求管理來決定的。那么,到底什么是需求管理,從這幾天的學習中,我從理論上對此問題做了一個分析,表達一些自已的想法。
            影響項目的最后成功的因素是多方面的,包括項目管理的九大知識領域(包括項目的整體管理、范圍管理、時間管理、費用管理、質量管理、溝通管理、成本管理、人力資源管理、采購管理)。然而,要這九大知識領域對項目成功產生的影響的輕重程度上進行比較的話,我個人認為其中項目范圍管理中的需求管理是最為重要的。本文主要講述范圍管理中的需求管理部分。
            需求管理是軟件項目中一項十分重要的工作,據調查顯示在眾多失敗的軟件項目中,由于需求原因導致的約占了很大的一部分,本人從事的工作經歷中有好2次就是因為需求不明確,導致最終的系統不可控,項目陷入困境。因此,需求工作將對軟件項目能否最終實現產生至關重要的影響。雖然如此,在項目開發工作中,很多人對需求的認識還遠遠不夠,從本人參與或接觸到的一些項目來看,小到幾萬元,大到上千萬元的軟件項目的需求都或多多少的存在問題。
            有的是開發者本身不重視原因,有的是技術原因、有的是人員組織原因、有的是溝通原因、有的是機制原因,以上種種原因都表明做好軟件需求開發是一項系統工作,而不是簡單的技術工作,只有系統的了解和掌握需求的基本概念、方法、手段、評估標準、風險等相關知識,并在實踐中加以應用,才能真正做好需求的開發和管理工作。在軟件項目的開發過程中,需求變更貫穿了軟件項目的整個生命周期,從軟件的項目立項,研發,維護,用戶的經驗在增加,對使用軟件的感受有變化,以及整個行業的新動態,都為軟件帶來不斷完善功能,優化性能,提高用戶友好性的要求。在軟件項目管理過程中,項目經理經常面對用戶的需求變更。如果不能有效處理這些需求變更,項目計劃會一再調整,軟件交付日期一再拖延,項目研發人員的士氣將越來越低落,將直接導致項目成本增加、質量下降及項目交付日期推后。這決定了項目組必須擁有需求管理策略。
            下面主要針對需求開發及需求管理兩個方面對需求進行分析。
            1. 需求開發,從目前我們的實際工作情況來看按順序主要分成如下幾個部分:
            請教行業專家
            行業客戶對信息化的需求越來越細化,對專業性以及行業能力的全面性要求越來越高,惟有深入行業,洞察其需求,研發出更適合客戶需求的產品,才能成功。因此有必要先請這方面的行業專家對于客戶的業務需求進行從流程上的梳理。為什么請行業專家,而不是直接請客戶進行交談,得到其實需求,個人認為主要是因為目前各政府部門、企事業單位對于信息化與業需求的整合這一塊缺少經驗,大部分情況還不能完全整理出完善、清晰的系統需求來。只有通過行業專家對其實業務流程進行梳理,一方面更容易與客戶產生共鳴,另一方面也可以大大減少因為知識方面的差異導致錯識需求的產生。
            和客戶交談
            你要面對“正確”的客戶區分不同層次的客戶需求,要面對不同層級,不同部門的客戶,把客戶分類,區分需求的優先級別.如果你做的項目業務是你熟悉的,那還好,如果是你不熟悉的,一定要花點精力學習一下這個行業業務的背景資料,這也是我上面談到的先請行業專家的原因。畢竟,客戶是不可能給你系統地介紹業務的。只有你通曉了行業業務,才能和用戶交流,并正確而有效地引導客戶,做好需求分析,你不能指望客戶能明確地說出需求。當然,這也是系統分析人員的職責所在。在開始做需求的時候,你最后花一點時間搞清楚你接觸的客戶是不是做實際業務的客戶,如果你面對的客戶不是將來的系統的實際使用者。你就有點麻煩了。可能他是客戶公司派過來的IT部的人,他會提一大堆東西,而這些東西可能根本不是實際業務需要的功能,而他一般還會興致勃勃地給你一些技術實現的建議。這個時候你就要小心了,如果你聽了他的話,你可能在最后才發現,你花了大量精力解決的問題,其實并不是客戶真正需要的。而你真正需要關注的,卻做得遠遠不夠。
           參考其他類似軟件和系統
            在經過與客戶的溝通,并形成初步的需求之后,不要急成正式的需求,請先參考一下以前的一些系統,去理解一下了解到的需求與原先系統的差異,并去發現是否有些需求會產生錯識需求。
            業務建模
            為需求建立模型,需求的圖形分析模型是軟件需求規格說明極好的補充說明。它們能提供不同的信息與關系以有助于找到不正確的、不一致的、遺漏的和冗余的需求。這樣的模型包括數據流圖、實體關系圖、狀態變換圖、對話框圖、對象類及交互作用圖。
            需求整理并形成需求規格說明書
            需求規格說明書的模板我想每家公司都是不一樣的,也沒有必要都一樣,但我認為每個需求規格說明書至少應包括
            軟件需求一旦通過了評審,就應該基線化,納入配置管理庫.而在配置管理庫中的文檔或代碼不能再輕易進行修改.當有需求要進行變更的時候,就必須提出申請,寫需求變更計劃,審核通過,才有權限進行需求變更.然后配置管理員一定要做好需求的跟蹤.,凡是跟變更需求有牽連的開發人員和測試人員都要同步的通知到和及時讓他們做好相應部分的各類文檔的修改。
            需求變更管理
            需求的變更管理我個人認為是最容易出問題,一般項目做不完也主要是由此產生。需求變更的出現主要是因為在項目的需求確定階段,用戶往往不能確切地定義自己需要什么。用戶常常以為自己清楚,但實際上他們提出的需求只是依據當前的工作所需,而采用的新設備、新技術通常會改變他們的工作方式;或者要開發的系統對用戶來說也是個未知數,他們以前沒有過相關的使用經驗。隨著開發工作的不斷進展,系統開始展現功能的雛形,用戶對系統的了解也逐步深入。于是,他們可能會想到各種新的功能和特色,或對以前提出的要求進行改動。他們了解得越多,新的要求也就越多,需求變更因此不可避免地一次又一次出現。如何有效的管理需求變更,下面是我公司目前的做法。公司采用Test Director作為需求管理工具,需求人員每次與客戶溝通后形成需求調查表,統一錄入Test Director,并進行綜合及整理后形成需求規格說明書, 之后由研發部、產品部、及銷售代表(如果有客戶參加就更好了)進行需求評審,建立需求基線。制訂簡單、有效的變更控制流程,并形成文檔。在建立了需求基線后提出的所有變更都必須遵循變更控制流程進行控制,同時每一筆重要的需求變更都需要客戶簽字確認才認為需求變更生效。需求變更后,受影響的軟件計劃、產品、活動都要進行相應的變更,以保持和更新的需求一致。因為Test Director提供了需求變更記錄,可以幫助我們形成良好的文檔,便于進行管理。
            2. 需求管理
            首先要針對需求做出分析,隨后應用于產品并提出方案。需求分析的模型正是產品的原型樣本,優秀的需求管理提高了這樣的可能性:它使最終產品更接近于解決需求,提高了用戶對產品的滿意度,從而使產品成為真正優質合格的產品。從這層意義上說,需求管理是產品質量的基礎。
            需求管理的目的是在客戶與開發方之間建立對需求的共同理解,維護需求與其它工作成果的一致性,并控制需求的變更。
            需求確認是指開發方和客戶共同對需求文檔進行評審,雙方對需求達成共識后作出書面承諾,使需求文檔具有商業合同效果。
            需求跟蹤是指通過比較需求文檔與后續工作成果之間的對應關系,建立與維護“需求跟蹤矩陣”,確保產品依據需求文檔進行開發。
            需求變更控制是指依據“變更申請-審批-更改-重新確認”的流程處理需求的變更,防止需求變更失去控制而導致項目發生混亂。
            根據上面描述的具體方法及步驟,由于需求分析的參與人員、業務模式、投資、時間等客觀因素的影響和需求本身具有主觀性和可描述性差的特點,因此,需求分析工作往往面臨著一些潛在的風險,應引起項目相關干系人的注意。這些風險主要表現如下:
            1)用戶不能正確表達自身的需求。在實際開發過程中,常常碰到用戶對自己真正的需求并不是十分明確的情況,他們認為計算機是萬能的,只要簡單的說說自己想干什么就是把需求說明白了,而對業務的規則、工作流程卻不愿多談,也講不清楚。這種情況往往會增加需求分析工作難度,分析人員需要花費更多的時間和精力與用戶交流,幫助他們梳理思路,搞清用戶的真實需求。從另一方面來看,他們對于計算機的理解肯定不是很到位,而我們如何引導,正確梳理出正確的需求就需要先從工作業務流程出發,而不是先從計算機方面來考慮問題。
            2)業務人員配合力度不夠。有的用戶日常工作繁忙,他們不愿意付出更多的時間和精力向分析人員講解業務,這樣會加大分析人員的工作難度和工作量,也可能導致因業務需求不足而使系統無法使用。針對此類問題我們一般的做法是在項目開始階段先確定好一個與客戶溝通過的需求調研計劃,當然這樣還是經常會有變動,但相對來講從責任上來講,客戶也會有一定的壓力,因為如果不配合可能會導致系統進度的延誤,其實這也不是客戶希望看到的。
            3)用戶需求的不斷變更。由于需求識別不全、業務發生變化、需求本身錯誤、需求不清楚等原因,需求在項目的整個生命周期都可能發生變化,因此,我們要認識到,軟件開發的過程實際上是同變化做斗爭的過程,需求變化是每個開發人員、項目管理人員都會遇到的問題,也是最頭痛的問題,一旦發生了需求變化,就不得不修改設計、重寫代碼、修改測試用例、調整項目計劃等等,需求的變化就像是萬惡之源,為項目的正常的進展帶來不盡的麻煩。針對這類需求變更的問題,個人認為是影響進度的最大的敵人,目前我們的做法是每次根據客戶的需求整理出一個書面的文件,由客戶簽字確認。當然這里還有一個很重要的問題就是不是每個需求都是必須做的,我們要學習如何拒絕客戶。
            4)需求的完整程度。需求如何做到沒有遺漏?這是一個大問題,大的系統要想窮舉需求幾乎是不可能的,即使小的系統,新的需求也總會不時地冒出來。一個系統很難確定明確的范圍并把所有需求一次性提出來,這會導致開發人員在項目進展中去不斷完善需求,先建立系統結構再完成需求說明,造成返工的可能性很大,會給開發人員帶來挫折感,降低他們完成項目的信心。
            5)需求的細化程度。需求到底描述到多細,才算可以結束了?雖然國家標準有需求說明的編寫規范,但具體到某一個需求上,很難給出一個具體的指標,可謂仁者見仁,智者見智,并沒有定論。需求越細,周期越長,可能的變化越多,對設計的限制越嚴格,對需求的共性提取要求也越高,相反,需求越粗,開發人員在技術設計時不清楚的地方就越多,影響技術設計。
            6)需求描述的多義性。需求描述的多義性一方面是指不同讀者對需求說明產生了不同的理解;另一方面是指同一讀者能用不同的方式來解釋某個需求說明。多義性會使用戶和開發人員等項目參與者產生不同的期望,也會使開發、測試人員為不同的理解而浪費時間,帶來不可避免的后果便是返工重做。
            7)忽略了用戶的特點分析。分析人員往往容易忽略了系統用戶的特點,系統是由不同的人使用其不同的特性,使用頻繁程度有所差異,使用者受教育程度和經驗水平不盡相同。如果忽略這些的話,將會導致有的用戶對產品感到失望。
            8)需求開發的時間保障。為了確保需求的正確性和完整性,項目負責人往往堅持要在需求階段花費較多的時間,但用戶和開發部門的領導卻會因為項目遲遲看不到實際成果而焦慮,他們往往會強迫項目盡快往前推進,需求開發人員也會被需求的復雜和善變折騰的筋疲力盡,他們也希望盡快結束需求階段。


            在實際的工作中,我列了一些需要關注的問題,以避免一些不必要的麻煩。
            1)抓住決策者最迫切和最關心的問題,引起重視。用戶方決策者對項目的關心重視程度是項目能否順利開展的關鍵,決策者的真實意圖也是用戶方的最終需求,因此,在開發過程中要利用一切機會了解決策者關心的問題,同時也要讓他們了解項目的情況。在諸如談判、專題匯報、協調會議、領導視察、階段性成果演示等過程中用簡短明確的語言或文字抓住領導最關心的問題,引導他們了解和重視項目的開發,當決策者認識到項目的重要性時,需求分析工作在人力、物力、時間上就有了保障。
            2)建立組織保障,明確的責任分工。項目開發一般都會成立相應的項目組或工程組,目前,常見的組織形式是:產品管理組、質量與測試組、程序開發組、用戶代表組和后勤保障組,各組的主要分工是:產品管理組負責確定和設置項目目標,根據需求的優先級確定功能規范,向相關人員通報項目進展。程序管理組負責系統分析,根據軟件開發標準協調日常開發工作確保及時交付開發任務,控制項目進度。程序開發組負責按照功能規范要求交付軟件系統。質量與測試組負責保證系統符合功能規范的要求,測試工作與開發工作是獨立并行的。用戶代表組負責代表用戶方提出需求,負責軟件的用戶方測試。后勤保障組負責確保項目順利進行的后勤保障工作。
            3)建立良好的溝通環境和氛圍。分析人員與用戶溝通的程度關系到需求分析的質量,因此建立一個良好的溝通氛圍、處理好分析人員與用戶之間的關系顯得尤其重要,一般情況,用戶作為投資方會有一些心理優勢,希望他們的意見得到足夠的重視,分析人員應該充分的認識到這一點,做好心理準備,盡量避免與他們發生爭執,因為我們的目的是幫助用戶說出他們的最終需要。在溝通時分析人員應注意以下幾個方面:1)態度上要尊重對方,但不謙恭。謙恭可能會讓用戶一時感到滿意,但對長期合作并沒有好處,尤其是在發生沖突的時候,用戶會習慣性地感到自己的優勢,而忽略分析人員地意見。2)分析人員要努力適應不同用戶的語言表達方式。每個人都有自己的表達方式,所以優秀的分析人員應該是一個優秀的“傾聽者”,他們能很快的適應用戶的語言風格,理解他們的意思。 3)善于表達自己,善于提問。分析人員在開口前應該先讓對方充分表達他的意思,在領會了后,自己再說,盡量不要搶話。4)工作外的交流有助于增進理解,加強溝通。
            4)需求質量控制要制度化需求的變化是軟件項目不可避免的事實,因此需求質量控制是一項艱苦的工作,要保證該項工作的順利實施,就必須有制度保證,這個制度可以在項目質量控制方案中制定,該方案主要是具體化、定量化的描述用戶要求,形成全面、一致、規范的軟件需求分析規格說明書,明確需求分析規格說明書的工作程序和要素,規范開發活動,為后續軟件設計、實現、測試、評審及驗收提供依據。在方案中要明確項目組各部門關于需求質量控制的職責,制定需求分析的工作程序,包括編制需求分析工作計劃、編制《需求分析說明書》、《需求分析規格說明書》的評審和確認、《需求分析規格說明書》修改控制、確定需求質量控制的質量記錄文檔規范等內容。
            本文論述圍繞于需求管理,需求管理是開發工作有效進行的確證。很明顯需求管理是一種很高層次的系統行為,涉及整個開發過程和產品本身。需求管理首先要針對需求做出分析,隨后應用于產品并提出方案。需求分析的模型正是產品的原型樣本,優秀的需求管理提高了這樣的可能性:它使最終產品更接近于解決需求,提高了用戶對產品的滿意度,從而使產品成為真正優質合格的產品。從這層意義上說,需求管理是產品質量的基礎。

          posted @ 2014-12-03 13:39 順其自然EVO 閱讀(215) | 評論 (0)編輯 收藏

          你應當知道的7個Java工具

           AlexZhitnitsky告訴我們這7個輔助工具的主要功能特點,這些工具每個java程序員都應該了解一下。這篇文章最初發表在takipi的博客–Java與Scala異常分析和性能監控.
            在準備進行鎖和負載測試之前,應該對一些最新的最具創新性的工具有一個快速了解。為了防止你錯過這些信息,rebellabs最近公布了對Java工具和技術全景的一個全球性調查結果。除了一些已有的或知名度很高的工具,現在市場上還充滿了很多不為人知的全新的工具和框架。
            在這篇文章中我們決定收集制作一個關于這類工具的簡略名單,他們中的大多數工具只是最近推出的。其中一些工具是為Java定制的,但也有一些是支持其他語言。但對于Java項目而言,他們都是非常好的,并且擁有同一個愿景:簡單化。讓我們開始吧。
            1.JClarity–性能監測工具
            它發布于去年9月。圍繞java性能,當前這款工具提供了兩個產品:Illuminate和Censum。
            Illuminate是一款性能監測工具,而censum是一種聚焦于垃圾收集日志分析的應用。
            它不僅僅提供了數據收集功能和可視化,對于檢測到的問題,這兩個工具能夠提供具有實踐性強的建議,幫助開發人員去解決問題。
            “我們要做的是把問題從數據收集階段轉移到數據分析和觀察階段”–JClarityCo-FounderBenEvans.
            主要特性:
            瓶頸檢測(磁盤I/O,垃圾收集,死鎖等)
            實施計劃–提出解決問題的具體建議,如“應用程序需要增加活動線程數”。
            解釋–一般性問題的定義以及引起該問題的常見原因,例如“垃圾回收時停頓時間耗時比例過高,可能意味著堆內存不夠,太小了”。
            獨特之處:進行監測和性能問題確認后,他會立即提供可行性的意見來解決這些問題
            幕后故事:JClarity是在倫敦建立的,他的創始人包括MartijnVerburg,KirkPepperdin和BenEvans,都是在java性能領域有著非常豐富經驗的人。
            想要獲取更多關于JClarity的信息,點擊這里
            2.Bintray-二元次的社交平臺
            當從一些”匿名”倉庫中導入庫文件時,Java開發人員在某種程度上被蒙在鼓里。Bintray給這些代碼添了“一張臉”,作為一個社會化平臺為java開發者服務,分享開源的軟件包(會不會有人說這是二元次的github?).它擁有超過85000個文件包,涵蓋18000個庫,展示了當前流行的和新版本的包。
            主要特性:
            上傳你的二進制文件,讓全世界都可以看到,并且可以和其他開發者進行交流,并得到一些反饋。
            使用Gradle/Maven/Yum/Apt工具下載包文件,或者直接從平臺下載。
            管理包的版本說明和相關文檔
            REST風格的API-查詢/檢索文件接口和自動分發接口
            獨特之處:Bintray的基礎功能類似于maven中央倉庫。但他增加了一個社交層,提供了一個將文件分發到CDN服務器的簡單辦法。
            幕后故事:JFrog基于Israel和California,開發了Bintray。該工具是去年4月公開的,并在上次JavaOne大會上贏得了Duke’schoiceaward獎項
            JFrog也開發Artifactory,Artifactory當然也是跑在Bintray上的。
            3.Librato–監控和可視化云服務
            Librato作為一個監控和管理云應用的托管服務,它可以瞬間完成自定義面板的創建,而不需要用戶去配置或者安裝任何軟件。
            相比其他面板,他的外觀和感受如黃油般順滑。
            “僅當你能夠從數據中獲得具有實際意義的信息時,數據才是有價值的”—JoeRuscio,Co-Founder&CTO
            主要特性:
            數據收集:集成了Heroku、AWS、數十種集成代理,以及綁定了java、Clojure等語言。
            自定義報告:性能指標和告警可以通過郵件、HipChat、Campfire以及HTTPPOST請求與你所想到的任何東西進行整合
            數據可視化:帶有注釋、相關性分析,共享和嵌入選項的美觀的圖片展示
            告警:當指標超過一定閾值時會自動發出通知告警
            特別之處:很難找到任何Librato不知道如何表述以及對數據的理解。
            幕后故事:FredvandenBosch,JoeRuscio,MikeHeffnerandDanStodin幾個人在SanFrancisco創建了Librato
            4.Takipi的建立基于一個簡單的目的:告訴開發人員到底在何時什么原因代碼出現異常。每當一個新的異常拋出,或者一個錯誤日志發生,Takipi就會捕獲它,給用戶展示可能引起該異常的變量狀態,經過的方法和設備。Takipi在錯誤發生時刻將會覆蓋實際執行代碼—所以在你分析異常時,就如同當異常發生時你正好在場。
            主要特性
            監控-捕獲/未捕獲的異常,http錯誤,和被日志記錄的錯誤
            優先排序-如果異常錯誤涉及到新增的代碼或者修改過的代碼,工具會統計集群中這樣的錯誤發生的頻率,以及錯誤發生的概率是否在遞增。
            分析-觀測實際代碼和變量狀態,甚至跨越不同的機器和應用
            獨特之處:
            生產環境的GodMode模式。錯誤發生時展示實際執行的異常代碼和變量狀態。這樣你分析異常時,就如同當異常發生時你在場。
            幕后故事:Takipi創建于2012年的SanFrancisco和TelAviv。每種異常類型和錯誤都有唯一的怪物來代表他。\ 5.Elasticsearch–搜索和分析平臺
            Elasticsearch已經存在一段時間了,但是他的1.0.0版本在2月份才發布。他是一個基于lucene的,托管在github上的開源項目,他有200位開發者。你可以從這checkout出代碼.Elasticsearch提供的主要特性是易于使用的,可擴展的,分布式的,rest風格的檢索。
            主要特性
            實時文檔存儲,文檔對象的每個field都建立了索引,都能被檢索
            構建適應于不同規模的應用的體系結構,在此之上實現分布式搜索。
            為其他平臺系統提供了具有rest風格的和原生javaapi。他也有hadoop的依賴包
            簡單可用性強,不需要對搜索原理有深入的理解。該平臺有免費模式,所以你可以快速開始應用起來。
            獨特之處:如他所說,他具有可伸縮性,靈活的構建和易用性。提供一個易用性的平臺,進行規模擴展時無需考慮核心功能與用戶自定義選項間妥協。
            幕后故事:Elasticsearch由ShayBanonback創建于2010年,最近募集到了7000萬刀的資金。在創建該項目前,Banon就經營一個Compass的開源項目,現在他是一個著名的搜索專家。那他進入搜索領域的動機呢?原來是為了讓他妻子能夠保存和檢索所喜歡的食譜,進而開發的一個應用。
            6.Spark–微型Web框架
            回到java語言,Spark是一個極具自由靈感的,能夠快速創建Web應用程序的微型Web框架。為了支持java8和lambdas,今年早些時候他被重寫了。Spark是一個開源項目,源代碼可以在github上可以看到(請點擊這里),目前開發該框架的人是PerWendel和過去幾年為了實現只需要付出很小的努力,便可以快速構建一個web應用這樣使命的一小撮人。
            主要特性:
            快速上手,配置簡單
            直觀的路由匹配器
            創建可復用組建的模板引擎,它支持Freemarker,ApacheVelocity和Mustache
            Spark可以運行在Jetty上,也可以在tomcat上跑
            獨特之處:圖片勝過千言萬語,圖片更加直觀,把代碼check出來感受一下吧
            幕后故事:Spark的創始人是PerWendel,瑞典人。目前與其他20個人開發Spark。去看看討論組,學習更多的關于Spark的知識,了解如何去給這個開源項目做貢獻,解決bug。
            7.Plumbr–內存泄漏檢測
            深入研究java虛擬機,其中的GC(GarbageCollector垃圾收集器)將那些不再使用的對象進行回收,釋放內存。盡管如此,有時候,開發人員仍舊會持有那些不再使用的對象引用,占用內存。這樣就會發生內存泄漏,這個時候,Plumer就該登場了。如果應用發生了內存泄漏問題,Plumer就會進行檢測,生成報告,并且提供切實可行的方案去fix掉這個問題。
            主要特性
            實時的內存泄漏檢測和告警
            一份包含時間,內存大小,速度(MB/h)以及泄漏事件的重要級別的報告。
            內存泄漏的代碼位置
            獨特之處:快,切中要點,從代碼中分析并給出建議幫你修復Bug
            幕后故事:Plumbr創建于Estonia,創始人是PriitPotter,IvoM?gi,NikitaSalnikov-Tarnovski和Vladimir?or。加入這樣一個擁有非常豐富經驗的java團隊吧,這些家伙都是非常厲害的救火隊員。嗯,是這樣的

          posted @ 2014-12-03 13:38 順其自然EVO 閱讀(261) | 評論 (0)編輯 收藏

          你真的懂產品管理嗎?實際上你一直都做錯了

           有人會雇傭個銷售代表,讓更新網站,然后在思考為什么銷售不肯來了呢?
            或者聘請個會計師,讓她去管理開發團隊,然后問她賬目為什么不是最新的?
            或者讓幾個程序猿花時間準備營銷郵件,然后問他們為什么代碼總被延期交付?
            或招聘個產品經理,讓他更新網站,管理開發團隊和撰寫營銷郵件,然后問他為什么產品戰略不夠高效,產品路線圖為什么不夠完善。
            好吧,前3種情況可能并不多見,但最后一種,產品管理的不幸總在許多公司上演,并在涉及到定義產品管理責任時,都會清晰地顯現出來。
            產品經理名言
            我們曾調查,什么事阻止了產品經理高效地工作?我們腦海里顯現出一幅清晰的畫面,產品經理做的一切,從技術支持到項目管理,就如別人所說,“像個打雜的”。
            大部分公司會聘請員工來長期或短期地關注一些成功的產品,但這些員工過來后,往往會偏離招聘地初衷,干些其它的事情。
            產品管理是一個跨職能部分角色。但這并不意味著產品經理就應該做其它部分的工作。他們應該確保工作是由合適的人在做,并與產品整體目標保持一致。
            成功需要協調
            為了最大限度地提高產品的成功,需要做好以下4點:
            業務活動和目標
            組織準備(內部和外部)
            產品上市的計劃和活動
            產品計劃和能力
            每個目標可被分解成一系列活動及里程碑,一些工作應該由產品經理完成,或在產品經理的監督下,由其它組完成。如果產品管理不注重在這幾個方面調整和優化每個產品的話,那么你在公司將失去核心價值。
            管理層需要確保該被其他組完成的工作,最后也是由這些組完成,而不是由(通常人員不足時)產品經理完成。
            否則,你就像讓銷售代表來更新你的網站一樣。當然,企業的效益也跟這一樣。

          posted @ 2014-12-03 13:38 順其自然EVO 閱讀(150) | 評論 (0)編輯 收藏

          Java數組的定義及用法

          數組是有序數據的集合,數組中的每一個元素具有同樣的數組名和下標來唯一地確定數組中的元素。
            1. 一維數組
            1.1 一維數組的定義
            type arrayName[];
            type[] arrayName;
            當中類型(type)能夠為Java中隨意的數據類型,包含簡單類型組合類型,數組名arrayName為一個合法的標識符,[]指明該變量是一個數組類型變量。
            另外一種形式對C++開發人員可能認為非常奇怪,只是對JAVA或C#這種開發語言來說,另外一種形式可能更直觀,由于這里定義的僅僅是個變量而已,系統并未對事實上例化,僅僅需指明變量的類型就可以,也不需在[]指定數組大小。(第一種形式是不是僅僅是為了兼容曾經的習慣,畢竟C語言的影響太大了?)
            比如:
            int intArray[];
            聲明了一個整型數組,數組中的每一個元素為整型數據。與C、C++不同,Java在數組的定義中并不為數組元素分配內存,因此[]中不用指出數組中元素個數,即數組長度,并且對于如上定義的一個數組是不能訪問它的不論什么元素的。我們必須為它分配內存空間,這時要用到運算符new,其格式例如以下:
            arrayName=new type[arraySize];
            當中,arraySize指明數組的長度。如:
            intArray=new int[3];
            為一個整型數組分配3個int型整數所占領的內存空間。
            通常,這兩部分能夠合在一起,格式例如以下:
            type arrayName=new type[arraySize];
            比如:
            int intArray=new int[3];
            1.2 一維數組元素的引用
            定義了一個數組,并用運算符new為它分配了內存空間后,就能夠引用數組中的每個元素了。數組元素的引用方式為:
            arrayName[index]
            當中:index為數組下標,它能夠為整型常數或表達式。如a[3],b[i](i為整型),c[6*I]等。下標 從0開始,一直到數組的長度減1。對于上面樣例中的in-tArray數來說,它有3個元素,分別為:
            intArray[0],intArray[1],intArray[2]。注意:沒有intArray[3]。
            另外,與C、C++中不同,Java對數組元素要進行越界檢查以保證安全性。同一時候,對于每一個數組都有一個屬性length指明它的長度,比如:intArray.length指明數組intArray的長度。
            執行結果例如以下:
            C:/>java ArrayTest
            a[4]=4
            a[3]=3
            a[2]=2
            a[1]=1
            a[0]=0
            該程序對數組中的每一個元素賦值,然后按逆序輸出。
            1.3 一維數組的初始化
            對數組元素能夠依照上述的樣例進行賦值。也能夠在定義數組的同一時候進行初始化。
            比如:
            int a[]={1,2,3,4,5};
            用逗號(,)分隔數組的各個元素,系統自己主動為數組分配一定空間。
            與C中不同,這時Java不要求數組為靜態(static),事實上這里的變量相似C中的指針,所以將其作為返回值給其他函數使用,仍然是有效的,在C中將局部變量返回給調用函數繼續使用是剛開始學習的人非常easy犯的錯誤。
            2. 多維數組
            與C、C++一樣,Java中多維數組被看作數組的數組。比如二維數組為一個特殊的一維數組,其每一個元素又是一個一維數組。以下我們主要以二維數為例來進行說明,高維的情況是相似的。
            2.1 二維數組的定義
            二維數組的定義方式為:
            type arrayName[][];
            比如:
            int intArray[][];
            與一維數組一樣,這時對數組元素也沒有分配內存空間,同要使用運算符new來分配內存,然后才干夠訪問每一個元素。
            對高維數組來說,分配內存空間有以下幾種方法:
            1. 直接為每一維分配空間,如:
            int a[][]=new int[2][3];
            2. 從最高維開始,分別為每一維分配空間,如:
            int a[][]=new int[2][];
            a[0]=new int[3];
            a[1]=new int[3];
            完畢1中同樣的功能。這一點與C、C++是不同的,在C、C++中必須一次指明每一維的長度。
            2.2 二維數組元素的引用
            對二維數組中每一個元素,引用方式為:arrayName[index1][index2] 當中index1、index2為下標,可為整型常數或表達式,如a[2][3]等,相同,每一維的下標都從0開始。
            2.3 二維數組的初始化
            有兩種方式:
            1. 直接對每一個元素進行賦值。
            2. 在定義數組的同一時候進行初始化。
            如:int a[][]={{2,3},{1,5},{3,4}};
            定義了一個3×2的數組,并對每一個元素賦值。

          posted @ 2014-12-03 13:37 順其自然EVO 閱讀(245) | 評論 (0)編輯 收藏

          Java對象實例化

           JAVA類,只要知道了類名(全名)就可以創建其實例對象,通用的方法是直接使用該類提供的構造方法,如
            NewObject o = new NewObject();
            NewObject o = new NewObject("test");
            NewObject o = new NewObject(new String[]{"aaa","bbb"});
            除此之外,還可以利用java.lang.Class<T>類來實現JAVA類的實例化。
            1、空構造方法
            如果類有空構造方法,如下面的類
          public class NewObject
          {
          String name;
          public NewObject(String[] name)
          {
          this.name = name[0];
          System.out.println(“ the object is created!”);
          }
          public void write()
          {
          System.out.println(this.name);
          }
          }
            使用以下代碼可實現實例化:
          NewObject no = null;
          try
          {
          no = (NewObject)Class.forName(className).newInstance();
          no.write();
          }
          catch (InstantiationException e)
          {
          e.printStackTrace();
          }
          catch (IllegalAccessException e)
          {
          e.printStackTrace();
          }
          catch (ClassNotFoundException e)
          {
          e.printStackTrace();
          }

          字體:        | 上一篇 下一篇 | 打印  | 我要投稿 

            2、帶參數構造方法
          public class NewObject
          {
          String name;
          public NewObject()
          {
          System.out.println(“ the object is created!”);
          }
          public void write()
          {
          System.out.println(“”);
          }
          }
            使用以下代碼可實現實例化:
          try
          {
          no=(NewObject)Class.forName(className).getConstructor(String.class).newInstance(names);
          //no=(NewObject)Class.forName(className).getConstructor(newObject[]{String.class}).newInstance(names);
          }
          catch(IllegalArgumentExceptione)
          {
          e.printStackTrace();
          }
          catch(SecurityExceptione)
          {
          e.printStackTrace();
          }
          catch(InstantiationExceptione)
          {
          e.printStackTrace();
          }
          catch(IllegalAccessExceptione)
          {
          e.printStackTrace();
          }
          catch(InvocationTargetExceptione)
          {
          e.printStackTrace();
          }
          catch(NoSuchMethodExceptione)
          {
          e.printStackTrace();
          }
          catch(ClassNotFoundExceptione)
          {
          e.printStackTrace();
          }
            3、帶數組參數構造方法
            public class NewObject
            {
            String name;
            public NewObject(String name)
            {
            this.name = name;
            System.out.println(“ the object is created!”);
            }
            public void write()
            {
            System.out.println(this.name);
            }
            }
            使用以下代碼可實現實例化:
          try
          {
          Constructor[] cs;
          cs = Class.forName(className).getConstructors();
          Constructor cc = Class.forName(className).getConstructor(String[].class);
          no = (NewObject)cc.newInstance(new Object[]{names});
          }
          catch (SecurityException e)
          {
          e.printStackTrace();
          }
          catch (ClassNotFoundException e)
          {
          e.printStackTrace();
          }
          catch (NoSuchMethodException e)
          {
          e.printStackTrace();
          }
          catch (IllegalArgumentException e)
          {
          e.printStackTrace();
          }
          catch (InstantiationException e)
          {
          e.printStackTrace();
          }
          catch (IllegalAccessException e)
          {
          e.printStackTrace();
          }
          catch (InvocationTargetException e)
          {
          e.printStackTrace();
          }

          posted @ 2014-12-03 13:37 順其自然EVO 閱讀(230) | 評論 (0)編輯 收藏

          Java 8的6個問題

          1. 并行Streams實際上可能會降低你的性能
            Java8帶來了最讓人期待的新特性之–并行。parallelStream() 方法在集合和流上實現了并行。它將它們分解成子問題,然后分配給不同的線程進行處理,這些任務可以分給不同的CPU核心處理,完成后再合并到一起。實現原理主要是使用了fork/join框架。好吧,聽起來很酷對吧!那一定可以在多核環境下使得操作大數據集合速度加快咯,對嗎?
            不,如果使用不正確的話實際上會使得你的代碼運行的更慢。我們進行了一些基準測試,發現要慢15%,甚至可能更糟糕。假設我們已經運行了多個線程,然后使用.parallelStream() 來增加更多的線程到線程池中,這很容易就超過多核心CPU處理的上限,從而增加了上下文切換次數,使得整體都變慢了。
            基準測試將一個集合分成不同的組(主要/非主要的):
            Map<Boolean, List<Integer>> groupByPrimary = numbers
            .parallelStream().collect(Collectors.groupingBy(s -> Utility.isPrime(s)));
            使得性能降低也有可能是其他的原因。假如我們分成多個任務來處理,其中一個任務可能因為某些原因使得處理時間比其他的任務長很多。.parallelStream() 將任務分解處理,可能要比作為一個完整的任務處理要慢。來看看這篇文章, Lukas Krecan給出的一些例子和代碼 。
            提醒:并行帶來了很多好處,但是同樣也會有一些其他的問題需要考慮到。當你已經在多線程環境中運行了,記住這點,自己要熟悉背后的運行機制。
            2. Lambda 表達式的缺點
            lambda表達式。哦,lambda表達式。沒有lambda表達式我們也能做到幾乎一切事情,但是lambda是那么的優雅,擺脫了煩人的代碼,所以很容易就愛上lambda。比如說早上起來我想遍歷世界杯的球員名單并且知道具體的人數(有趣的事實:加起來有254個)。
            List lengths = new ArrayList();
            for (String countries : Arrays.asList(args)) {
            lengths.add(check(country));
            }
            現在我們用一個漂亮的lambda表達式來實現同樣的功能:
            Stream lengths = countries.stream().map(countries -< check(country));
            哇塞!這真是超級厲害。增加一些像lambda表達式這樣的新元素到Java當中,盡管看起來更像是一件好事,但是實際上卻是偏離了Java原本的規范。字節碼是完全面向對象的,伴隨著lambda的加入 ,這使得實際的代碼與運行時的字節碼結構上差異變大。閱讀更多關于lambda表達式的負面影響可以看Tal Weiss這篇文章。
            從更深層次來看,你寫什么代碼和調試什么代碼是兩碼事。堆棧跟蹤越來越大,使得難以調試代碼。一些很簡單的事情譬如添加一個空字符串到list中,本來是這樣一個很短的堆棧跟蹤
            at LmbdaMain.check(LmbdaMain.java:19)
            at LmbdaMain.main(LmbdaMain.java:34)
            變成這樣:
          at LmbdaMain.check(LmbdaMain.java:19)
          at LmbdaMain.lambda$0(LmbdaMain.java:37)
          at LmbdaMain$$Lambda$1/821270929.apply(Unknown Source)
          at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
          at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
          at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
          at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
          at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
          at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
          at java.util.stream.LongPipeline.reduce(LongPipeline.java:438)
          at java.util.stream.LongPipeline.sum(LongPipeline.java:396)
          at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
          at LmbdaMain.main(LmbdaMain.java:39
            lambda表達式帶來的另一個問題是關于重載:使用他們調用一個方法時會有一些傳參,這些參數可能是多種類型的,這樣會使得在某些情況下導致一些引起歧義的調用。Lukas Eder 用示例代碼進行了說明。
            提醒:要意識到這一點,跟蹤有時候可能會很痛苦,但是這不足以讓我們遠離寶貴的lambda表達式。
            3. Default方法令人分心
            Default方法允許一個功能接口中有一個默認實現,這無疑是Java8新特性中最酷的一個,但是它與我們之前使用的方式有些沖突。那么既然如此,為什么要引入default方法呢?如果不引入呢?
            Defalut方法背后的主要動機是,如果我們要給現有的接口增加一個方法,我們可以不用重寫實現來達到這個目的,并且使它與舊版本兼容。例如,拿這段來自Oracle Java教程中 添加指定一個時區功能的代碼來說:
          public interface TimeClient {
          // ...
          static public ZoneId getZoneId (String zoneString) {
          try {
          return ZoneId.of(zoneString);
          } catch (DateTimeException e) {
          System.err.println("Invalid time zone: " + zoneString +
          "; using default time zone instead.");
          return ZoneId.systemDefault();
          }
          }
          default public ZonedDateTime getZonedDateTime(String zoneString) {
          return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
          }
          }
            就是這樣,問題迎刃而解了。是這樣么?Default方法將接口和實現分離混合了。似乎我們不用再糾結他們本身的分層結構了,現在我們需要解決新的問題了。想要了解更多,閱讀Oleg Shelajev在RebelLabs上發表的文章吧。
            提醒:當你手上有一把錘子的時候,看什么都像是釘子。記住它們原本的用法,保持原來的接口而重構引入新的抽象類是沒有意義的。
           4. 該如何拯救你,Jagsaw?
            Jigsaw項目的目標是使Java模塊化,將JRE分拆成可以相互操作的組件。這背后最主要的動機是渴望有一個更好、更快、更強大的Java嵌入式。我試圖避免提及“物聯網”,但我還是說了。減少JAR的體積,改進性能,增強安全性等等是這個雄心勃勃的項目所承諾的。
            但是,它在哪呢?Oracle的首席Java架構師, Mark Reinhold說:  Jigsaw,通過了探索階段 ,最近才進入第二階段,現在開始進行產品的設計與實現。該項目原本計劃在Java8完成。現在推遲到Java9,有可能成為其最主要的新特性。
            提醒:如果這正是你在等待的, Java9應該在2016年間發布。同時,想要密切關注甚至參與其中的話,你可以加入到這個郵件列表。
            5. 那些仍然存在的問題
            受檢異常
            沒有人喜歡繁瑣的代碼,那也是為什么lambdas表達式那么受歡迎的的原因。想想討厭的異常,無論你是否需要在邏輯上catch或者要處理受檢異常,你都需要catch它們。即使有些永遠也不會發生,像下面這個異常就是永遠也不會發生的:
            try {
            httpConn.setRequestMethod("GET");
            }?catch (ProtocolException pe) { /* Why don’t you call me anymore? */ }
            原始類型
            它們依然還在,想要正確使用它們是一件很痛苦的事情。原始類型導致Java沒能夠成為一種純面向對象語言,而移除它們對性能也沒有顯著的影響。順便提一句,新的JVM語言都沒有包含原始類型。
            運算符重載
            James Gosling,Java之父,曾經在接受采訪時說:“我拋棄運算符重載是因為我個人主觀的原因,因為在C++中我見過太多的人在濫用它。”有道理,但是很多人持不同的觀點。其他的JVM語言也提供這一功能,但是另一方面,它導致有些代碼像下面這樣:
            javascriptEntryPoints <<= (sourceDirectory in Compile)(base =>
            ((base / "assets" ** "*.js") --- (base / "assets" ** "_*")).get
            )
            事實上這行代碼來自Scala  Play框架,我現在都有點暈了。
            提醒:這些是真正的問題么?我們都有自己的怪癖,而這些就是Java的怪癖。在未來的版本中可能有會發生一些意外,它將會改變,但向后兼容性等等使得它們現在還在使用。
            6. 函數式編程–為時尚早
            函數式編程出現在java之前,但是它相當的尷尬。Java8在這方面有所改善例如lambdas等等。這是讓人受歡迎的,但卻不如早期所描繪的那樣變化巨大??隙ū菾ava7更優雅,但是仍需要努力增加一些真正需要的功能。
            其中一個在這個問題上最激烈的評論來自Pierre-yves Saumont,他寫了一系列的文章詳細的講述了函數式編程規范和其在Java中實現的差異。
            所以,選擇Java還是Scala呢?Java采用現代函數范式是對使用多年Lambda的Scala的一種肯定。Lambdas讓我們覺得很迷惑,但是也有許多像traits,lazy evaluation和immutables等一些特性,使得它們相當的不同。
            提醒:不要為lambdas分心,在Java8中使用函數式編程仍然是比較麻煩的。

          posted @ 2014-12-03 13:36 順其自然EVO 閱讀(224) | 評論 (0)編輯 收藏

          聊聊Oracle外鍵約束的幾個操作選項

          關系型數據庫是以數據表和關系作為兩大對象基礎。數據表是以二維關系將數據組織在DBMS中,而關系建立數據表之間的關聯,搭建現實對象模型。主外鍵是任何數據庫系統都需存在的約束對象,從對象模型中的業務邏輯加以抽象,作為物理設計的一個部分在數據庫中加以實現。
            Oracle外鍵是維護參照完整性的重要手段,大多數情況下的外鍵都是緊密關聯關系。外鍵約束的作用,是保證字表某個字段取值全都與另一個數據表主鍵字段相對應。也就是說,只要外鍵約束存在并有效,就不允許無參照取值出現在字表列中。具體在Oracle數據庫中,外鍵約束還是存在一些操作選項的。本篇主要從實驗入手,介紹常見操作選項。
            二、環境介紹
            筆者選擇Oracle 11gR2進行測試,具體版本號為11.2.0.4。
          SQL> select * from v$version;
          BANNER
          --------------------------------------------------------------------------------
          Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
          PL/SQL Release 11.2.0.4.0 - Production
          CORE      11.2.0.4.0     Production
          TNS for 64-bit Windows: Version 11.2.0.4.0 - Production
          NLSRTL Version 11.2.0.4.0 – Production
            創建數據表Prim和Child,對應數據插入。
          SQL> create table prim (v_id number(3), v_name varchar2(100));
          Table created
          SQL> alter table prim add constraint pk_prim primary key (v_id);
          Table altered
          SQL> create table child (c_id number(3), v_id number(3), c_name varchar2(100));
          Table created
          SQL> alter table child add constraint pk_child primary key (c_id);
          Table altered
            二、默認外鍵行為
            首先我們查看默認外鍵行為方式。
            SQL> alter table CHILD
            2    add constraint FK_CHILD_PRIM foreign key (V_ID)
            3    references prim (V_ID)
            4  ;
            在沒有額外參數加入的情況下,Oracle外鍵將嚴格按照標準外鍵方式工作。
            --在有子記錄情況下,強制刪除主表記錄;
            SQL> delete prim where v_id=2;
            delete prim where v_id=2
            ORA-02292:違反完整約束條件(A.FK_CHILD_PRIM) - 已找到子記錄
            --在存在子表記錄情況下,更改主表記錄;
            SQL> update prim set v_id=4 where v_id=2;
            update prim set v_id=4 where v_id=2
            ORA-02292:違反完整約束條件(A.FK_CHILD_PRIM) - 已找到子記錄
            --修改子表記錄
            SQL> update child set v_id=5 where v_id=2;
            update child set v_id=5 where v_id=2
            ORA-02291: 違反完整約束條件 (A.FK_CHILD_PRIM) - 未找到父項關鍵字
            上面實驗說明:在默認的Oracle外鍵配置條件下,只要有子表記錄存在,主表記錄是不允許修改或者刪除的。子表記錄也必須時刻保證參照完整性。
           三、On delete cascade
            對于應用開發人員而言,嚴格外鍵約束關系是比較麻煩的。如果直接操作數據庫記錄,就意味著需要手工處理主子表關系,處理刪除順序問題。On delete cascade允許了一種“先刪除主表,連帶刪除子表記錄”的功能,同時確保數據表整體參照完整性。
            創建on delete cascade外鍵,只需要在創建外鍵中添加相應的子句。
            SQL> alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on delete cascade;
            Table altered
            測試:
          SQL> delete prim where v_id=2;
          1 row deleted
          SQL> select * from prim;
          V_ID V_NAME
          ---- --------------------------------------------------------------------------------
          1 kk
          3 iowkd
          SQL> select * from child;
          C_ID V_ID C_NAME
          ---- ---- --------------------------------------------------------------------------------
          1    1 kll
          2    1 ddkll
          3    1 43kll
          SQL> rollback;
          Rollback complete
            刪除主表操作成功,對應的子表記錄被連帶自動刪除。但是其他操作依然是不允許進行。
            SQL> update prim set v_id=4 where v_id=2;
            update prim set v_id=4 where v_id=2
            ORA-02292:違反完整約束條件(A.FK_CHILD_PRIM) - 已找到子記錄
            SQL> update child set v_id=5 where v_id=2;
            update child set v_id=5 where v_id=2
            ORA-02291: 違反完整約束條件 (A.FK_CHILD_PRIM) - 未找到父項關鍵字
            On delete cascade被稱為“級聯刪除”,對開發人員來講是一種方便的策略,可以直接“無視”子記錄而刪掉主記錄。但是,一般情況下,數據庫設計人員和DBA一般都不推薦這樣的策略。
            究其原因,還是由于系統業務規則而定。On delete cascade的確在一定程度上很方便,但是這種自動操作在一些業務系統中是可能存在風險的。例如:一個系統中存在一個參數引用關系,這個參數被引用到諸如合同的主記錄中。按照業務規則,如果這個參數被引用過,就不應當被刪除。如果我們設置了on delete cascade外鍵,連帶的合同記錄就自動的被“干掉”了。開發參數模塊的同事一般情況下,也沒有足夠的“覺悟”去做手工判定?;谶@個因素,我們推薦采用默認的強約束關聯,起碼不會引起數據丟失的情況。
            四、On Delete Set Null
            除了直接刪除記錄,Oracle還提供了一種保留子表記錄的策略。注意:外鍵約束本身不限制字段為空的問題。如果一個外鍵被設置為on delete set null,當刪除主表記錄的時候,無論是否存在子表對應記錄,主表記錄都會被刪除,子表對應列被清空。
            SQL> alter table child drop constraint fk_child_prim;
            Table altered
            SQL> alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on delete set null;
            Table altered
            刪除主表記錄。
          SQL> delete prim where v_id=2;
          1 row deleted
          SQL> select * from prim;
          V_ID V_NAME
          ---- --------------------------------------------------------------------------------
          1 kk
          3 iowkd
          SQL> select * from child;
          C_ID V_ID C_NAME
          ---- ---- --------------------------------------------------------------------------------
          1    1 kll
          2    1 ddkll
          3    1 43kll
          4      43kll
          5      4ll
          SQL> rollback;
          Rollback complete
            主表記錄刪除,子表外鍵列被清空。其他約束動作沒有變化。
            SQL> update prim set v_id=4 where v_id=2;
            update prim set v_id=4 where v_id=2
            ORA-02292:違反完整約束條件(A.FK_CHILD_PRIM) - 已找到子記錄
            SQL> update child set v_id=5 where v_id=2;
            update child set v_id=5 where v_id=2
            ORA-02291: 違反完整約束條件 (A.FK_CHILD_PRIM) - 未找到父項關鍵字
            那么,下一個問題是:如果外鍵列不能為空,會怎么樣呢?
          SQL> desc child;
          Name   Type          Nullable Default Comments
          ------ ------------- -------- ------- --------
          C_ID   NUMBER(3)
          V_ID   NUMBER(3)     Y
          C_NAME VARCHAR2(100) Y
          SQL> alter table child modify v_id not null;
          Table altered
          SQL> desc child;
          Name   Type          Nullable Default Comments
          ------ ------------- -------- ------- --------
          C_ID   NUMBER(3)
          V_ID   NUMBER(3)
          C_NAME VARCHAR2(100) Y
          SQL> delete prim where v_id=2;
          delete prim where v_id=2
          ORA-01407: 無法更新 ("A"."CHILD"."V_ID")為 NULL
            更改失敗~
            五、傳說中的on update cascade
            On update cascade被稱為“級聯更新”,是關系數據庫理論中存在的一種外鍵操作類型。這種類型指的是:當主表的記錄被修改(主鍵值修改),對應子表的外鍵列值連帶的進行修改。
            SQL> alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on update cascade;
            alter table child add constraint FK_CHILD_PRIM foreign key(v_id) references prim(v_id) on update cascade
            ORA-00905: 缺失關鍵字
            目前的Oracle版本中,似乎還不支持on update cascade功能。Oracle在官方服務中對這個問題的闡述是:在實際系統開發環境中,直接修改主鍵的情況是比較少的。所以,也許在將來的版本中,這個特性會進行支持。
            六、結論
            Oracle外鍵是我們日常比較常見的約束類型。在很多專家和業界人員的討論中,我們經常聽到“使用外鍵還是系統編碼”的爭論。支持外鍵策略的一般都是數據庫專家和“大撒把”的設計師,借助數據庫天然的特性,可以高效實現功能。支持系統編碼的人員大都是“對象派”等新派人員,相信可以借助系統前端解決所有問題。
            筆者對外鍵的觀點是“適度外鍵,雙重驗證”。外鍵要設計在最緊密的引用關系中,對驗證動作,前端和數據庫端都要進行操作。外鍵雖然可以保證最后安全渠道,但是不能將正確易于接受的信息反饋到前端。前端開發雖然比較直觀,但是的確消耗精力。所以,把握適度是重要的出發點。

          posted @ 2014-12-03 13:35 順其自然EVO 閱讀(626) | 評論 (0)編輯 收藏

          SQL優化中索引列使用函數之靈異事件

           在SQL優化內容中有一種說法說的是避免在索引列上使用函數、運算等操作,否則Oracle優化器將不使用索引而使用全表掃描,但是也有一些例外的情況,今天我們就來看看該靈異事件。
            一般而言,以下情況都會使Oracle的優化器走全表掃描,舉例:
            1.         substr(hbs_bh,1,4)=’5400’,優化處理:hbs_bh like ‘5400%’
            2.         trunc(sk_rq)=trunc(sysdate), 優化處理:sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)
            3.         進行了顯式或隱式的運算的字段不能進行索引,如:
            ss_df+20>50,優化處理:ss_df>30
            'X' || hbs_bh>’X5400021452’,優化處理:hbs_bh>'5400021542'
            sk_rq+5=sysdate,優化處理:sk_rq=sysdate-5
            4.         條件內包括了多個本表的字段運算時不能進行索引,如:ys_df>cx_df,無法進行優化
            qc_bh || kh_bh='5400250000',優化處理:qc_bh='5400' and kh_bh='250000'
            5.  避免出現隱式類型轉化
            hbs_bh=5401002554,優化處理:hbs_bh='5401002554',注:此條件對hbs_bh 進行隱式的to_number轉換,因為hbs_bh字段是字符型。
            有一些其它的例外情況,如果select 后邊只有索引列且where查詢中的索引列含有非空約束的時候,以上規則不適用,如下示例:
            先給出所有腳本及結論:
            drop table t  purge;
            Create Table t  nologging As select *  from    dba_objects d ;
            create   index ind_objectname on  t(object_name);
            select t.object_name from t where t.object_name ='T';        --走索引
            select t.object_name from t where UPPER(t.object_name) ='T';       --不走索引
            select t.object_name from t where UPPER(t.object_name) ='T' and t.object_name IS NOT NULL ;           --走索引  (INDEX FAST FULL SCAN)
            select t.object_name from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;     --走索引  (INDEX FAST FULL SCAN)
            select t.object_name,t.owner from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;     --不走索引
            測試代碼:
          C:\Users\華榮>sqlplus lhr/lhr@orclasm
          SQL*Plus: Release 11.2.0.1.0 Production on 星期三 11月 12 10:52:29 2014
          Copyright (c) 1982, 2010, Oracle.  All rights reserved.
          連接到:
          Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
          With the Partitioning, Automatic Storage Management, OLAP, Data Mining
          and Real Application Testing options
          SQL>
          SQL>
          SQL> drop table t  purge;
          表已刪除。
          SQL> Create Table t  nologging As select *  from    dba_objects d ;
          表已創建。
          SQL>  create   index ind_objectname on  t(object_name);
          索引已創建。
           ---- t表所有列均可以為空
          SQL> desc t
          Name                      Null?    Type
          ----------------------------------------- -------- ----------------------------
          OWNER                               VARCHAR2(30)
          OBJECT_NAME                         VARCHAR2(128)
          SUBOBJECT_NAME                      VARCHAR2(30)
          OBJECT_ID                           NUMBER
          DATA_OBJECT_ID                      NUMBER
          OBJECT_TYPE                         VARCHAR2(19)
          CREATED                             DATE
          LAST_DDL_TIME                       DATE
          TIMESTAMP                           VARCHAR2(19)
          STATUS                              VARCHAR2(7)
          TEMPORARY                           VARCHAR2(1)
          GENERATED                           VARCHAR2(1)
          SECONDARY                           VARCHAR2(1)
          NAMESPACE                           NUMBER
          EDITION_NAME                        VARCHAR2(30)
          SQL>
          SQL>  set autotrace traceonly;
          SQL>  select t.object_name from t where t.object_name ='T';
          執行計劃
          ----------------------------------------------------------
          Plan hash value: 4280870634
          -----------------------------------------------------------------------------------
          | Id  | Operation        | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
          -----------------------------------------------------------------------------------
          |   0 | SELECT STATEMENT |                |     1 |    66 |     3   (0)| 00:00:01 |
          |*  1 |  INDEX RANGE SCAN| IND_OBJECTNAME |     1 |    66 |     3   (0)| 00:00:01 |
          -----------------------------------------------------------------------------------
          Predicate Information (identified by operation id):
          ---------------------------------------------------
          1 - access("T"."OBJECT_NAME"='T')
          Note
          -----
          - dynamic sampling used for this statement (level=2)
          - SQL plan baseline "SQL_PLAN_503ygb00mbj6k165e82cd" used for this statement
          統計信息
          ----------------------------------------------------------
          34  recursive calls
          43  db block gets
          127  consistent gets
          398  physical reads
          15476  redo size
          349  bytes sent via SQL*Net to client
          359  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
          SQL>  select t.object_name from t where UPPER(t.object_name) ='T';
          執行計劃
          ----------------------------------------------------------
          Plan hash value: 1601196873
          --------------------------------------------------------------------------
          | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
          --------------------------------------------------------------------------
          |   0 | SELECT STATEMENT  |      |    12 |   792 |   305   (1)| 00:00:04 |
          |*  1 |  TABLE ACCESS FULL| T    |    12 |   792 |   305   (1)| 00:00:04 |
          --------------------------------------------------------------------------
          Predicate Information (identified by operation id):
          ---------------------------------------------------
          1 - filter(UPPER("T"."OBJECT_NAME")='T')
          Note
          -----
          - dynamic sampling used for this statement (level=2)
          - SQL plan baseline "SQL_PLAN_9p76pys5gdb2b94ecae5c" used for this statement
          統計信息
          ----------------------------------------------------------
          29  recursive calls
          43  db block gets
          1209  consistent gets
          1092  physical reads
          15484  redo size
          349  bytes sent via SQL*Net to client
          359  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
          SQL>  select t.object_name from t where UPPER(t.object_name) ='T' and t.object_name IS NOT NULL ;
          執行計劃
          ----------------------------------------------------------
          Plan hash value: 3379870158
          ---------------------------------------------------------------------------------------
          | Id  | Operation            | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
          ---------------------------------------------------------------------------------------
          |   0 | SELECT STATEMENT     |                |    51 |  3366 |   110   (1)| 00:00:02 |
          |*  1 |  INDEX FAST FULL SCAN| IND_OBJECTNAME |    51 |  3366 |   110   (1)| 00:00:02 |
          ---------------------------------------------------------------------------------------
          Predicate Information (identified by operation id):
          ---------------------------------------------------
          1 - filter("T"."OBJECT_NAME" IS NOT NULL AND UPPER("T"."OBJECT_NAME")='T')
          Note
          -----
          - dynamic sampling used for this statement (level=2)
          - SQL plan baseline "SQL_PLAN_czkarb71kthws18b0c28f" used for this statement
          統計信息
          ----------------------------------------------------------
          29  recursive calls
          43  db block gets
          505  consistent gets
          384  physical reads
          15612  redo size
          349  bytes sent via SQL*Net to client
          359  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
          SQL>  select t.object_name,t.owner from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;
          執行計劃
          ----------------------------------------------------------
          Plan hash value: 1601196873
          --------------------------------------------------------------------------
          | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
          --------------------------------------------------------------------------
          |   0 | SELECT STATEMENT  |      |    51 |  4233 |   304   (1)| 00:00:04 |
          |*  1 |  TABLE ACCESS FULL| T    |    51 |  4233 |   304   (1)| 00:00:04 |
          --------------------------------------------------------------------------
          Predicate Information (identified by operation id):
          ---------------------------------------------------
          1 - filter("T"."OBJECT_NAME" IS NOT NULL AND
          UPPER("T"."OBJECT_NAME")||'AAA'='TAAA')
          Note
          -----
          - dynamic sampling used for this statement (level=2)
          - SQL plan baseline "SQL_PLAN_au9a1c4hwdtb894ecae5c" used for this statement
          統計信息
          ----------------------------------------------------------
          30  recursive calls
          44  db block gets
          1210  consistent gets
          1091  physical reads
          15748  redo size
          408  bytes sent via SQL*Net to client
          359  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
          SQL> select t.object_name from t where UPPER(t.object_name) ||'AAA' ='T'||'AAA' and t.object_name IS NOT NULL ;
          執行計劃
          ----------------------------------------------------------
          Plan hash value: 3379870158
          ---------------------------------------------------------------------------------------
          | Id  | Operation            | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
          ---------------------------------------------------------------------------------------
          |   0 | SELECT STATEMENT     |                |    51 |  3366 |   110   (1)| 00:00:02 |
          |*  1 |  INDEX FAST FULL SCAN| IND_OBJECTNAME |    51 |  3366 |   110   (1)| 00:00:02 |
          ---------------------------------------------------------------------------------------
          Predicate Information (identified by operation id):
          ---------------------------------------------------
          1 - filter("T"."OBJECT_NAME" IS NOT NULL AND
          UPPER("T"."OBJECT_NAME")||'AAA'='TAAA')
          Note
          -----
          - dynamic sampling used for this statement (level=2)
          - SQL plan baseline "SQL_PLAN_1gu36rnh3s2a318b0c28f" used for this statement
          統計信息
          ----------------------------------------------------------
          28  recursive calls
          44  db block gets
          505  consistent gets
          6  physical reads
          15544  redo size
          349  bytes sent via SQL*Net to client
          359  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
          SQL>
            其實很好理解的,索引可以看成是小表,一般而言索引總是比表本身要小得多,如果select 后需要檢索的項目在索引中就可以檢索的到那么Oracle優化器為啥還去大表中尋找數據呢?

          posted @ 2014-12-03 13:35 順其自然EVO 閱讀(590) | 評論 (0)編輯 收藏

          利用binlog進行數據庫的還原

          前言:在學習mysql備份的時候,深深的感受到mysql的備份還原功能沒有oracle強大;比如一個很常見的恢復場景:基于時間點的恢復,oracle通過rman工具就能夠很快的實現數據庫的恢復,但是mysql在進行不完全恢復的時候很大的一部分要依賴于mysqlbinlog這個工具運行binlog語句來實現,本文檔介紹通過mysqlbinlog實現各種場景的恢復;
            一、測試環境說明:使用mysqlbinlog工具的前提需要一個數據庫的完整性備份,所以需要事先對數據庫做一個完整的備份,本文檔通過mysqlbackup進行數據庫的全備
            二、測試步驟說明:
            數據庫的插入準備工作
            2.1 在時間點A進行一個數據庫的完整備份;
            2.2 在時間點B創建一個數據庫BKT,并在BKT下面創建一個表JOHN,并插入5條數據;
            2.3 在時間點C往表JOHN繼續插入數據到10條;
            數據庫的恢復工作
            2.4 恢復數據庫到時間點A,然后檢查數據庫表的狀態;
            2.5 恢復數據庫到時間點B,檢查相應的系統狀態;
            2.6 恢復數據庫到時間點C,并檢查恢復的狀態;
            三、場景模擬測試步驟(備份恢復是一件很重要的事情)
            3.1 執行數據庫的全備份;
            [root@mysql01 backup]# mysqlbackup --user=root --password --backup-dir=/backup backup-and-apply-log //運行數據庫的完整備份
            3.2 創建數據庫、表并插入數據
          mysql> SELECT CURRENT_TIMESTAMP;
          +---------------------+
          | CURRENT_TIMESTAMP |
          +---------------------+
          | 2014-11-26 17:51:27 |
          +---------------------+
          1 row in set (0.01 sec)
          mysql> show databases; //尚未創建數據庫BKT
          +--------------------+
          | Database |
          +--------------------+
          | information_schema |
          | john |
          | mysql |
          | performance_schema |
          +--------------------+
          4 rows in set (0.03 sec)
          mysql> Ctrl-C --
          Aborted
          [root@mysql02 data]# mysql -uroot -p
          Enter password:
          Welcome to the MySQL monitor. Commands end with ; or \\g.
          Your MySQL connection id is 2
          Server version: 5.5.36-log Source distribution
          Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
          Oracle is a registered trademark of Oracle Corporation and/or its
          affiliates. Other names may be trademarks of their respective
          owners.
          Type \'help;\' or \'\\h\' for help. Type \'\\c\' to clear the current input statement.
          mysql> show master status;
          +------------------+----------+--------------+------------------+
          | File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
          +------------------+----------+--------------+------------------+
          | mysql-bin.000001 | 107 | | | //當前數據庫log的pos狀態
          +------------------+----------+--------------+------------------+
          1 row in set (0.00 sec)
          mysql> SELECT CURRENT_TIMESTAMP; //當前的時間戳 當前時間點A
          +---------------------+
          | CURRENT_TIMESTAMP |
          +---------------------+
          | 2014-11-26 17:54:12 |
          +---------------------+
          1 row in set (0.00 sec)
          mysql> create database BKT; //創建數據庫BKT
          Query OK, 1 row affected (0.01 sec)
          mysql> create table john (id varchar(32));
          ERROR 1046 (3D000): No database selected
          mysql> use bkt;
          ERROR 1049 (42000): Unknown database \'bkt\'
          mysql> use BKT;
          Database changed
          mysql> create table john (id varchar(32));
          Query OK, 0 rows affected (0.02 sec)
          mysql> insert into john values(\'1\');
          Query OK, 1 row affected (0.01 sec)
          mysql> insert into john values(\'2\');
          Query OK, 1 row affected (0.01 sec)
          mysql> insert into john values(\'3\');
          Query OK, 1 row affected (0.00 sec)
          mysql> insert into john values(\'4\');
          Query OK, 1 row affected (0.01 sec)
          mysql> insert into john values(\'5\');
          Query OK, 1 row affected (0.01 sec)
          mysql> SELECT CURRENT_TIMESTAMP; //插入5條數據后數據庫的時間點B,記錄該點便于數據庫的恢復
          +---------------------+
          | CURRENT_TIMESTAMP |
          +---------------------+
          | 2014-11-26 17:55:53 |
          +---------------------+
          1 row in set (0.00 sec)
          mysql> show master status;
          +------------------+----------+--------------+------------------+
          | File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
          +------------------+----------+--------------+------------------+
          | mysql-bin.000001 | 1204 | | | //當前binlog的pos位置
          +------------------+----------+--------------+------------------+
          1 row in set (0.00 sec)
           3.3 設置時間點C的測試
          mysql> insert into john values(\'6\');
          Query OK, 1 row affected (0.02 sec)
          mysql> insert into john values(\'7\');
          Query OK, 1 row affected (0.01 sec)
          mysql> insert into john values(\'8\');
          Query OK, 1 row affected (0.01 sec)
          mysql> insert into john values(\'9\');
          Query OK, 1 row affected (0.01 sec)
          mysql> insert into john values(\'10\');
          Query OK, 1 row affected (0.03 sec)
          mysql> show master status;
          +------------------+----------+--------------+------------------+
          | File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
          +------------------+----------+--------------+------------------+
          | mysql-bin.000001 | 2125 | | |
          +------------------+----------+--------------+------------------+
          1 row in set (0.00 sec)
          mysql> SELECT CURRENT_TIMESTAMP;
          +---------------------+
          | CURRENT_TIMESTAMP |
          +---------------------+
          | 2014-11-26 17:58:08 |
          +---------------------+
          1 row in set (0.00 sec)
            3.4 以上的操作完成之后,便可以執行數據庫的恢復測試
          [root@mysql02 data]# mysqlbackup --defaults-file=/backup/server-my.cnf --datadir=/data/mysql --backup-dir=/backup/ copy-back
          MySQL Enterprise Backup version 3.11.0 Linux-3.8.13-16.2.1.el6uek.x86_64-x86_64 [2014/08/26]
          Copyright (c) 2003, 2014, Oracle and/or its affiliates. All Rights Reserved.
          mysqlbackup: INFO: Starting with following command line ...
          mysqlbackup --defaults-file=/backup/server-my.cnf --datadir=/data/mysql
          --backup-dir=/backup/ copy-back
          mysqlbackup: INFO:
          IMPORTANT: Please check that mysqlbackup run completes successfully.
          At the end of a successful \'copy-back\' run mysqlbackup
          prints \"mysqlbackup completed OK!\".
          141126 17:59:58 mysqlbackup: INFO: MEB logfile created at /backup/meta/MEB_2014-11-26.17-59-58_copy_back.log
          --------------------------------------------------------------------
          Server Repository Options:
          --------------------------------------------------------------------
          datadir = /data/mysql
          innodb_data_home_dir = /data/mysql
          innodb_data_file_path = ibdata1:10M:autoextend
          innodb_log_group_home_dir = /data/mysql/
          innodb_log_files_in_group = 2
          innodb_log_file_size = 5242880
          innodb_page_size = Null
          innodb_checksum_algorithm = none
          --------------------------------------------------------------------
          Backup Config Options:
          --------------------------------------------------------------------
          datadir = /backup/datadir
          innodb_data_home_dir = /backup/datadir
          innodb_data_file_path = ibdata1:10M:autoextend
          innodb_log_group_home_dir = /backup/datadir
          innodb_log_files_in_group = 2
          innodb_log_file_size = 5242880
          innodb_page_size = 16384
          innodb_checksum_algorithm = none
          mysqlbackup: INFO: Creating 14 buffers each of size 16777216.
          141126 17:59:58 mysqlbackup: INFO: Copy-back operation starts with following threads
          1 read-threads 1 write-threads
          mysqlbackup: INFO: Could not find binlog index file. If this is online backup then server may not have started with --log-bin.
          Hence, binlogs will not be copied for this backup. Point-In-Time-Recovery will not be possible.
          141126 17:59:58 mysqlbackup: INFO: Copying /backup/datadir/ibdata1.
          mysqlbackup: Progress in MB: 200 400 600
          141126 18:00:22 mysqlbackup: INFO: Copying the database directory \'john\'
          141126 18:00:23 mysqlbackup: INFO: Copying the database directory \'mysql\'
          141126 18:00:23 mysqlbackup: INFO: Copying the database directory \'performance_schema\'
          141126 18:00:23 mysqlbackup: INFO: Completing the copy of all non-innodb files.
          141126 18:00:23 mysqlbackup: INFO: Copying the log file \'ib_logfile0\'
          141126 18:00:23 mysqlbackup: INFO: Copying the log file \'ib_logfile1\'
          141126 18:00:24 mysqlbackup: INFO: Creating server config files server-my.cnf and server-all.cnf in /data/mysql
          141126 18:00:24 mysqlbackup: INFO: Copy-back operation completed successfully.
          141126 18:00:24 mysqlbackup: INFO: Finished copying backup files to \'/data/mysql\'
          mysqlbackup completed //數據庫恢復完成
            授權并打開數據庫
            [root@mysql02 data]# chmod -R 777 mysql //需要授權后才能打開
            [root@mysql02 data]# cd mysql
            [root@mysql02 mysql]# ll
            總用量 733220
          -rwxrwxrwx. 1 root root 305 11月 26 18:00 backup_variables.txt
          -rwxrwxrwx. 1 root root 740294656 11月 26 18:00 ibdata1
          -rwxrwxrwx. 1 root root 5242880 11月 26 18:00 ib_logfile0
          -rwxrwxrwx. 1 root root 5242880 11月 26 18:00 ib_logfile1
          drwxrwxrwx. 2 root root 4096 11月 26 18:00 john
          drwxrwxrwx. 2 root root 4096 11月 26 18:00 mysql
          drwxrwxrwx. 2 root root 4096 11月 26 18:00 performance_schema
          -rwxrwxrwx. 1 root root 8488 11月 26 18:00 server-all.cnf
          -rwxrwxrwx. 1 root root 1815 11月 26 18:00 server-my.cnf //沒有BKT數據庫
          [root@mysql02 mysql]# service mysqld start //啟動數據庫
            3.5 進行數據庫的恢復到時間點B
            [root@mysql02 mysql2]# pwd //備份的時候,需要備份binlog日志,之前的binlog目錄為/data/mysql2
            /data/mysql2
            [root@mysql02 mysql2]# mysqlbinlog --start-position=107 --stop-position=1203 mysql-bin.000001| mysql -uroot -p //根據post的位置進行恢復,當前的pos位置為107,恢復到pos位置到1203
          Enter password:
          [root@mysql02 mysql2]# mysql -uroot -p
          Enter password:
          Welcome to the MySQL monitor. Commands end with ; or \\g.
          Your MySQL connection id is 3
          Server version: 5.5.36-log Source distribution
          Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
          Oracle is a registered trademark of Oracle Corporation and/or its
          affiliates. Other names may be trademarks of their respective
          owners.
          Type \'help;\' or \'\\h\' for help. Type \'\\c\' to clear the current input statement.
          mysql> show databases;
          +--------------------+
          | Database |
          +--------------------+
          | information_schema |
          | BKT |
          | john |
          | mysql |
          | performance_schema |
          +--------------------+
          5 rows in set (0.02 sec)
          mysql> use BKT
          Database changed
          mysql> show tables;
          +---------------+
          | Tables_in_BKT |
          +---------------+
          | john |
          +---------------+
          1 row in set (0.00 sec)
          mysql> select * from john;
          +------+
          | id |
          +------+
          | 1 |
          | 2 |
          | 3 |
          | 4 |
          | 5 |
          +------+
          5 rows in set (0.01 sec) //查看數據庫恢復成功
            3.6 恢復數據庫到時間點C
          [root@mysql02 mysql2]# mysqlbinlog --start-date=\"2014-11-27 09:21:56\" --stop-date=\"2014-11-27 09:22:33\" mysql-bin.000001| mysql -uroot -p123456 //本次通過基于時間點的恢復,恢復到時間點C
          Warning: Using unique option prefix start-date instead of start-datetime is deprecated and will be removed in a future release. Please use the full name instead.
          Warning: Using unique option prefix stop-date instead of stop-datetime is deprecated and will be removed in a future release. Please use the full name instead.
          [root@mysql02 mysql2]# mysql -uroot -p
          Enter password:
          Welcome to the MySQL monitor. Commands end with ; or \\g.
          Your MySQL connection id is 6
          Server version: 5.5.36-log Source distribution
          Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
          Oracle is a registered trademark of Oracle Corporation and/or its
          affiliates. Other names may be trademarks of their respective
          owners.
          Type \'help;\' or \'\\h\' for help. Type \'\\c\' to clear the current input statement.
          mysql> show databases;
          +--------------------+
          | Database |
          +--------------------+
          | information_schema |
          | BKT |
          | john |
          | mysql |
          | performance_schema |
          +--------------------+
          5 rows in set (0.00 sec)
          mysql> use BKT
          Database changed
          mysql> select * from john;
          +------+
          | id |
          +------+
          | 1 |
          | 2 |
          | 3 |
          | 4 |
          | 5 |
          | 6 |
          | 7 |
          | 8 |
          | 9 |
          | 10 |
          +------+
          10 rows in set (0.00 sec) //經過檢查成功恢復到時間點C
            四、mysqlbinlog的其他總結:以上是利用binlog文件進行基于時間點和binlog的POS位置恢復的測試,mysqlbinlog的使用還有很多功能,運行mysqlbinlog --help可以查看相應參數;
            4.1 查看binlog的內容:[root@mysql02 mysql2]# mysqlbinlog mysql-bin.000001
            4.2 mysqlbinlog的其他常用參數:
            -h  根據數據庫的IP
            -P  根據數據庫所占用的端口來分
            -server-id 根據數據庫serverid來還原(在集群中很有用)
            -d  根據數據庫名稱
            例如: [root@mysql02 mysql2]# mysqlbinlog -d BKT mysql-bin.000001 //還原BKT數據庫的信息

          posted @ 2014-12-03 13:34 順其自然EVO 閱讀(1371) | 評論 (0)編輯 收藏

          探索Oracle之數據庫升級一 升級補丁修復概述

           一、 升級路線圖
            無論你是誰,要想做數據庫升級,我想一定離不開如下這張升級線路圖;企業中數據庫的升級是一個浩大的工程,但是卻又必不可少,小在打一個PSU解決一個簡單的問題或實現某個功能,大到打安裝Patch對數據庫版本升級,都是作為一名合格的DBA必備的技能。再后面的幾篇博客當中將詳細講述如何將數據庫從11.2.0.3.0升級到11.2.0.4并且打上最新的OPATCH之后再升級到Oracle 12c。
            二、 升級類型:
            11.2.0.1.0 ----------11.2.0.4.0---------11.2.0.4.4-----------12.2.0.1.0
            CPU                      PSU
            Update                             upgrade
            1. 什么是PSU/CPU?
            CPU: Critical Patch Update   (SPU: Security Patch Update)
            Oracle對于其產品每個季度發行一次的安全補丁包,通常是為了修復產品中的安全隱患。
            PSU: Patch Set Updates
            Oracle對于其產品每個季度發行一次的補丁包,包含了bug的修復。Oracle選取被用戶下載數量多的,并且被驗證過具有較低風險的補丁放入到每個季度的PSU中。在每個PSU中不但包含Bug的修復而且還包含了最新的CPU。
            2. 如何查找最新的PSU
            每個數據庫版本都有自己的PSU,PSU版本號體現在數據庫版本的最后一位,比如最新的10.2.0.5的PSU是10.2.0.5.6,而11.2.0.3的最新PSU則是11.2.0.4.3。
            MOS站點中OracleRecommended Patches — Oracle Database [ID 756671.1] 文檔中查到各個產品版本最新的PSU。
            如果你記不住這個文檔號,那么在MOS中以“PSU”為關鍵字搜索,通常這個文檔會顯示在搜索結果的最前面。
            注意:必須購買了Oracle基本服務獲取了CSI號以后才有權限登陸MOS站點。
            Upgrade與Update
            首先,我們針對所使用的數據庫可能會進行如下措施,版本升級或補丁包升級,那何為版本升級、何為補丁包升級呢?
            比如我的當前數據庫是10GR2版本,但公司最近有個升級計劃,把這套數據庫升級到當下最新的11GR2,這種大版本間升級動作即為Upgrade。根據公司計劃在原廠工程師和DBA共同努力下,數據庫已升級到11GR2,當下版本為11.2.0.4.0。這時候原廠工程師推薦把最新的PSU給打上,獲得老板的批準之后,我們又把數據庫進行補丁包的升級,應用了PSU Patch:18522509之后,數據庫版本現在成為11.2.0.4.3,這個過程即是Update。
            不得不再次提醒,Upgrade和Update都希望在獲得原廠的支持下進行,尤其是Upgrade,這對于企業來說是個非常大的動作!
            PSR(Patch Set Release)和 PSU(Patch Set Update)
            8i、9i、10g、11g、12c這是其主要版本號,每一版本會陸續有兩至三個發行版,如10.1,10.2,和11.1,11.2分別是10g和11g的兩個發行版。對于每一個發行版軟件中發現的BUG,給出相應的修復補丁。每隔一定時期,會將所有補丁集成到軟件中,經過集成測試后,進行發布,也稱為PSR(Patch Set Release)。以10.2為例,10.2.0.1.0是基礎發行版,至今已有三個PSR發布,每個PSR修改5位版本號的第4位,最新10.2的PSR為10.2.0.4.0。(11.1.0.6.0是11.1的基礎發行版,11.1.0.7.0是第一次PSR)。
            在某個PSR之后編寫的補丁,在還沒有加入到下一個PSR之前,以個別補?。↖nterimPatch)的形式提供給客戶。某個個別補丁是針對Oracle公司發現的或客戶報告的某一個BUG編寫的補丁,多個個別補丁之間一同安裝時可能會有沖突,即同一個目標模塊分別進行了不同的修改。另外,即便在安裝時沒有發現沖突,由于沒有進行嚴格的集成測試,運行過程中由于相互作用是否會發生意外也不能完全排除。
            除去修改功能和性能BUG的補丁,還有應對安全漏洞的安全補丁。Oracle公司定期(一年四期)發布安全補丁集,稱之為CPU(Critical Patch Updates)。
            由于數據庫在信息系統的核心地位,對其性能和安全性的要求非常高。理應及時安裝所有重要補丁。另外一個方面,基于同樣的理由,要求數據庫系統必須非常穩定,安裝補丁而導致的系統故障和性能下降同樣不可接受。DBA經常面臨一個非常困難的選擇:對于多個修復重要BUG的個別補丁是否安裝。不安裝,失去預防故障發生的機會,以后故障發生時,自己是無作為;安裝,如果這些補丁中存在著倒退BUG,或者相互影響,以后發生由于安裝補丁而造成的故障時,自己則是無事生非!而等待下一個PSR,一般又需要一年時間。因此,出了PSU(Patch Set Update)
            三、Oracle 版本說明
            Oracle 的版本號很多,先看11g的一個版本號說明:
            注意:在oracle 9.2 版本之后, oracle 的maintenance release number 是在第二數字位更改。而在之前,是在第三個數字位。
            1. Major Database ReleaseNumber
            第一個數字位,它代表的是一個新版本軟件,也標志著一些新的功能。如11g,10g。
            2. Database MaintenanceRelease Number
            第二個數字位,代表一個maintenancerelease 級別,也可能包含一些新的特性。
            3. Fusion Middleware ReleaseNumber
            第三個數字位,反應Oracle 中間件(Oracle Fusion Middleware)的版本號。
            4. Component-Specific ReleaseNumber
            第四個數字位,主要是針對組件的發布級別。不同的組件具有不同的號碼。 比如Oracle 的patch包。
            5. Platform-Specific ReleaseNumber
            第五個數字位,這個數字位標識一個平臺的版本。 通常表示patch 號。

          posted @ 2014-12-03 13:33 順其自然EVO 閱讀(543) | 評論 (0)編輯 收藏

          僅列出標題
          共394頁: First 上一頁 7 8 9 10 11 12 13 14 15 下一頁 Last 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 阿合奇县| 衢州市| 汕头市| 辽阳市| 龙里县| 什邡市| 屯留县| 曲周县| 陆川县| 闽侯县| 满城县| 日照市| 尉犁县| 漯河市| 屏东县| 青田县| 鄂州市| 浑源县| 宁海县| 临泽县| 孟村| 赣州市| 湘乡市| 克拉玛依市| 德钦县| 敦煌市| 林甸县| 华安县| 南昌县| 长丰县| 上虞市| 旌德县| 东宁县| 车险| 禄丰县| 鄂托克前旗| 饶阳县| 普兰县| 张北县| 青岛市| 太仆寺旗|