<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

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

    Linux后門入侵檢測工具,附bash漏洞解決方法

     一、rootkit簡介
      rootkit是Linux平臺下最常見的一種木馬后門工具,它主要通過替換系統文件來達到入侵和和隱蔽的目的,這種木馬比普通木馬后門更加危險和隱蔽,普通的檢測工具和檢查手段很難發現這種木馬。rootkit攻擊能力極強,對系統的危害很大,它通過一套工具來建立后門和隱藏行跡,從而讓攻擊者保住權限,以使它在任何時候都可以使用root權限登錄到系統。
      rootkit主要有兩種類型:文件級別和內核級別,下面分別進行簡單介紹。
      1、文件級別rootkit
      文件級別的rootkit一般是通過程序漏洞或者系統漏洞進入系統后,通過修改系統的重要文件來達到隱藏自己的目的。在系統遭受rootkit攻擊后,合法的文件被木馬程序替代,變成了外殼程序,而其內部是隱藏著的后門程序。通常容易被rootkit替換的系統程序有login、ls、ps、ifconfig、du、find、netstat等,其中login程序是最經常被替換的,因為當訪問Linux時,無論是通過本地登錄還是遠程登錄,/bin/login程序都會運行,系統將通過/bin/login來收集并核對用戶的賬號和密碼,而rootkit就是利用這個程序的特點,使用一個帶有根權限后門密碼的/bin/login來替換系統的/bin/login,這樣攻擊者通過輸入設定好的密碼就能輕松進入系統。此時,即使系統管理員修改root密碼或者清除root密碼,攻擊者還是一樣能通過root用戶登錄系統。攻擊者通常在進入Linux系統后,會進行一系列的攻擊動作,最常見的是安裝嗅探器收集本機或者網絡中其他服務器的重要數據。在默認情況下,Linux中也有一些系統文件會監控這些工具動作,例如ifconfig命令,所以,攻擊者為了避免被發現,會想方設法替換其他系統文件,常見的就是ls、ps、ifconfig、du、find、netstat等。如果這些文件都被替換,那么在系統層面就很難發現rootkit已經在系統中運行了。
      這就是文件級別的rootkit,對系統維護很大,目前最有效的防御方法是定期對系統重要文件的完整性進行檢查,如果發現文件被修改或者被替換,那么很可能系統已經遭受了rootkit入侵。檢查件完整性的工具很多,常見的有Tripwire、 aide等,可以通過這些工具定期檢查文件系統的完整性,以檢測系統是否被rootkit入侵。
      2、內核級別的rootkit
      內核級rootkit是比文件級rootkit更高級的一種入侵方式,它可以使攻擊者獲得對系統底層的完全控制權,此時攻擊者可以修改系統內核,進而截獲運行程序向內核提交的命令,并將其重定向到入侵者所選擇的程序并運行此程序,也就是說,當用戶要運行程序A時,被入侵者修改過的內核會假裝執行A程序,而實際上卻執行了程序B。
      內核級rootkit主要依附在內核上,它并不對系統文件做任何修改,因此一般的檢測工具很難檢測到它的存在,這樣一旦系統內核被植入rootkit,攻擊者就可以對系統為所欲為而不被發現。目前對于內核級的rootkit還沒有很好的防御工具,因此,做好系統安全防范就非常重要,將系統維持在最小權限內工作,只要攻擊者不能獲取root權限,就無法在內核中植入rootkit。
      二、rootkit后門檢測工具chkrootkit
      chkrootkit是一個Linux系統下查找并檢測rootkit后門的工具,它的官方址: http://www.chkrootkit.org/。 chkrootkit沒有包含在官方的CentOS源中,因此要采取手動編譯的方法來安裝,不過這種安裝方法也更加安全。下面簡單介紹下chkrootkit的安裝過程。
      1.準備gcc編譯環境
      對于CentOS系統,需要安裝gcc編譯環境,執行下述三條命令:
      [root@server ~]# yum -y install gcc
      [root@server ~]# yum -y install gcc-c++
      [root@server ~]# yum -y install make
      2、安裝chkrootkit
      為了安全起見,建議直接從官方網站下載chkrootkit源碼,然后進行安裝,操作如下:
      [root@server ~]# tar zxvf chkrootkit.tar.gz
      [root@server ~]# cd chkrootkit-*
      [root@server ~]# make sense
      # 注意,上面的編譯命令為make sense
      [root@server ~]# cd ..
      [root@server ~]# cp -r chkrootkit-* /usr/local/chkrootkit
      [root@server ~]# rm -rf chkrootkit-*
      3、使用chkrootkit
      安裝完的chkrootkit程序位于/usr/local/chkrootkit目錄下,執行如下命令即可顯示chkrootkit的詳細用法:
      [root@server chkrootkit]# /usr/local/chkrootkit/chkrootkit  -h
      chkrootkit各個參數的含義如下所示。
      參數含義
      -h顯示幫助信息
      -v顯示版本信息
      -l顯示測試內容
      -ddebug模式,顯示檢測過程的相關指令程序
      -q安靜模式,只顯示有問題的內容
      -x高級模式,顯示所有檢測結果
      -r dir設置指定的目錄為根目錄
      -p dir1:dir2:dirN指定chkrootkit檢測時使用系統命令的目錄
      -n跳過NFS連接的目錄
    chkrootkit的使用比較簡單,直接執行chkrootkit命令即可自動開始檢測系統。下面是某個系統的檢測結果:
    [root@server chkrootkit]# /usr/local/chkrootkit/chkrootkit
    Checking `ifconfig'... INFECTED
    Checking `ls'... INFECTED
    Checking `login'... INFECTED
    Checking `netstat'... INFECTED
    Checking `ps'... INFECTED
    Checking `top'... INFECTED
    Checking `sshd'... not infected
    Checking `syslogd'... not tested
    Checking `tar'... not infected
    Checking `tcpd'... not infected
    Checking `tcpdump'... not infected
    Checking `telnetd'... not found
      從輸出可以看出,此系統的ifconfig、ls、login、netstat、ps和top命令已經被感染。針對被感染rootkit的系統,最安全而有效的方法就是備份數據重新安裝系統。
      4、chkrootkit的缺點
      chkrootkit在檢查rootkit的過程中使用了部分系統命令,因此,如果服務器被黑客入侵,那么依賴的系統命令可能也已經被入侵者替換,此時chkrootkit的檢測結果將變得完全不可信。為了避免chkrootkit的這個問題,可以在服務器對外開放前,事先將chkrootkit使用的系統命令進行備份,在需要的時候使用備份的原始系統命令讓chkrootkit對rootkit進行檢測。這個過程可以通過下面的操作實現:
      [root@server ~]# mkdir /usr/share/.commands
      [root@server ~]# cp `which --skip-alias awk cut echo find egrep id head ls netstat ps strings sed uname` /usr/share/.commands
      [root@server ~]# /usr/local/chkrootkit/chkrootkit -p /usr/share/.commands/
      [root@server share]# cd /usr/share/
      [root@server share]# tar zcvf commands.tar.gz .commands
      [root@server share]#  rm -rf commands.tar.gz
      上面這段操作是在/usr/share/下建立了一個.commands隱藏文件,然后將chkrootkit使用的系統命令進行備份到這個目錄下。為了安全起見,可以將.commands目錄壓縮打包,然后下載到一個安全的地方進行備份,以后如果服務器遭受入侵,就可以將這個備份上傳到服務器任意路徑下,然后通過chkrootkit命令的“-p”參數指定這個路徑進行檢測即可。
      三、rootkit后門檢測工具RKHunter
      RKHunter是一款專業的檢測系統是否感染rootkit的工具,它通過執行一系列的腳本來確認服務器是否已經感染rootkit。在官方的資料中,RKHunter可以作的事情有:
      MD5校驗測試,檢測文件是否有改動
      檢測rootkit使用的二進制和系統工具文件
      檢測特洛伊木馬程序的特征碼
      檢測常用程序的文件屬性是否異常
      檢測系統相關的測試
      檢測隱藏文件
      檢測可疑的核心模塊LKM
      檢測系統已啟動的監聽端口
      下面詳細講述下RKHunter的安裝與使用。
      1、安裝RKHunter
      RKHunter的官方網頁地址為:http://www.rootkit.nl/projects/rootkit_hunter.html,建議從這個網站下載RKHunter,這里下載的版本是rkhunter-1.4.0.tar.gz。RKHunter的安裝非常簡單,過程如下:
      [root@server ~]# ls
      rkhunter-1.4.0.tar.gz
      [root@server ~]# pwd
      /root
      [root@server ~]# tar -zxvf rkhunter-1.4.0.tar.gz
      [root@server ~]# cd rkhunter-1.4.0
      [root@server rkhunter-1.4.0]# ./installer.sh  --layout default --install
      這里采用RKHunter的默認安裝方式,rkhunter命令被安裝到了/usr/local/bin目錄下。
      2、使用rkhunter指令
      rkhunter命令的參數較多,但是使用非常簡單,直接運行rkhunter即可顯示此命令的用法。下面簡單介紹下rkhunter常用的幾個參數選項。
      [root@server ~]#/usr/local/bin/rkhunter–help
      Rkhunter常用參數以及含義如下所示。
      參數             含義
      -c, –check必選參數,表示檢測當前系統
      –configfile <file>使用特定的配置文件
      –cronjob作為cron任務定期運行
      –sk, –skip-keypress自動完成所有檢測,跳過鍵盤輸入
      –summary顯示檢測結果的統計信息
      –update檢測更新內容
      -V, –version顯示版本信息
      –versioncheck檢測最新版本
      下面是通過rkhunter對某個系統的檢測示例:
    [root@server rkhunter-1.4.0]# /usr/local/bin/rkhunter   -c
    [ Rootkit Hunter version 1.4.0 ]
    #下面是第一部分,先進行系統命令的檢查,主要是檢測系統的二進制文件,因為這些文件最容易被rootkit攻擊。顯示OK字樣表示正常,顯示Warning表示有異常,需要引起注意,而顯示“Not found”字樣,一般無需理會
    Checking system commands...
    Performing 'strings' command checks
    Checking 'strings' command                           [ OK ]
    Performing 'shared libraries' checks
    Checking for preloading variables                        [ None found ]
    Checking for preloaded libraries                         [ None found ]
    Checking LD_LIBRARY_PATH variable                 [ Not found ]
    Performing file properties checks
    Checking for prerequisites                              [ Warning ]
    /usr/local/bin/rkhunter  [ OK ]
    /sbin/chkconfig                                       [ OK ]
    ....(略)....
    [Press <ENTER> to continue]
    #下面是第二部分,主要檢測常見的rootkit程序,顯示“Not found”表示系統未感染此rootkit
    Checking for rootkits...
    Performing check of known rootkit files and directories
    55808 Trojan - Variant A                                 [ Not found ]
    ADM Worm                                           [ Not found ]
    AjaKit Rootkit                                         [ Not found ]
    Adore Rootkit                                          [ Not found ]
    aPa Kit                                               [ Not found ]
    Apache Worm                                          [ Not found ]
    Ambient (ark) Rootkit                                    [ Not found ]
    Balaur Rootkit           [ Not found ]
    BeastKit Rootkit                                         [ Not found ]
    beX2 Rootkit                                             [ Not found ]
    BOBKit Rootkit                    [ Not found ]
    ....(略)....
    [Press <ENTER> to continue]

    posted @ 2014-10-16 14:11 順其自然EVO 閱讀(301) | 評論 (0)編輯 收藏

    優化MySQL,還是使用緩存?

    今天我想對一個Greenfield項目上可以采用的各種性能優化策略作個對比。換言之,該項目沒有之前決策強加給它的各種約束限制,也還沒有被優化過。
      具體來說,我想比較的兩種優化策略是優化MySQL和緩存。提前指出,這些優化是正交的,唯一讓你選擇其中一者而不是另一者的原因是他們都耗費了資源,即開發時間。
      優化MySQL
      優化MySQL時,一般會先查看發送給mysql的查詢語句,然后運行explain命令。稍加審查后很常見的做法是增加索引或者對模式做一些調整。
      優點
      1、一個經過優化的查詢對于所有使用應用的用戶來說都是快速的。因為索引通過對數復雜度的速度來檢索數據(又名分制,正如你搜索一個電話簿一樣,逐步縮小搜索范圍),而且隨著數據量的遞增也能維持良好的性能。對一個未經索引化的查詢的結果做緩存隨著數據的增長有時候則可能會表現得更差。隨著數據的增長,那些未命中緩存的用戶可能會得到很糟糕的體驗,這樣的應用是不可用的。
      2、優化MySQL不需要擔心緩存失效或者緩存數據過期的問題。
      3、優化MySQL可以簡化技術架構,在開發環境下復制和工作會更加容易。
      缺點
      1、有一些查詢不能光通過索引得到性能上的改善,可能還需要改變模式,在某些情況下這對于一些應用可能會很麻煩。
      2、有些模式的更改可能用于反規范化(數據備份)。盡管對于DBA來說,這是一項常用的技術,它需要所有權以確保所有的地方都是由應用程序更新,或需要安裝觸發器來保證這種變化。
      3、一些優化手段可能是MySQL所特有的。也就是說,如果底層軟件被移植到多個數據庫上工作,那么很難確保除了增加索引外一些更復雜的優化技術可以通用。
      使用緩存
      這種優化需要人來分析應用的實際情況,然后將處理代價昂貴的部分從MySQL中剝離出來用第三方緩存替代,比如memcached或Redis。
      優點
      1、緩存對于一些MySql自身很難優化的查詢來說會工作地很好,比如大規模的聚合或者分組的查詢。
      2、緩存對于提高系統的吞吐率來說可能是個不錯的方案。比如對于多人同時訪問應用時響應速度很慢的情況。
      3、緩存可能更容易構建在另一個應用之上。比如:你的應用可能是另一個用MySQL存儲數據的軟件包的前端,而要對這個軟件包做任何數據庫方面的改動都非常難。
      缺點
      1、如果數據對外提供多種存取范式(例如,在不同的頁面上用不同的形式展示),那么讓緩存過期或者更新可能會很難,同時/或者可能需要容忍已過期的數據。一個可行的替代方案是設計一套更加精細的緩存機制,當然它也有缺點,即多次獲取緩存會增加時延。
      2、緩存一個產生代價昂貴的對象對于那些未命中緩存的用戶(見優化MySQL的優勢#1)而言可能會產生潛在的性能差異。一些好的性能實踐表明你應該盡量縮小用戶之間的差異性,而不僅僅是平均化(緩存傾向于這么做)。
      3、幼稚的緩存實現無力應對一些微妙的漏洞,比如雪崩效應。就在上周我幫助了一個人,他的數據庫服務器被多個試圖同時再生同樣緩存內容的用戶請求沖垮。正確的策略是引入一定級別的鎖來將緩存再生的請求序列化。
      總結
      一般情況下,我會建議用戶先對MySQL進行優化,因為這是我認為開始階段最合適的解決方案。但長期來看,大部分應用都會有一些用例需要一定程度上同時實現以上這些方案。

    posted @ 2014-10-16 09:59 順其自然EVO 閱讀(637) | 評論 (0)編輯 收藏

    Java并發編程:同步容器

    為了方便編寫出線程安全的程序,Java里面提供了一些線程安全類和并發工具,比如:同步容器、并發容器、阻塞隊列、Synchronizer(比如CountDownLatch)。今天我們就來討論下同步容器。
      一.為什么會出現同步容器?
      在Java的集合容器框架中,主要有四大類別:List、Set、Queue、Map。
      List、Set、Queue接口分別繼承了Collection接口,Map本身是一個接口。
      注意Collection和Map是一個頂層接口,而List、Set、Queue則繼承了Collection接口,分別代表數組、集合和隊列這三大類容器。
      像ArrayList、LinkedList都是實現了List接口,HashSet實現了Set接口,而Deque(雙向隊列,允許在隊首、隊尾進行入隊和出隊操作)繼承了Queue接口,PriorityQueue實現了Queue接口。另外LinkedList(實際上是雙向鏈表)實現了了Deque接口。
      像ArrayList、LinkedList、HashMap這些容器都是非線程安全的。
      如果有多個線程并發地訪問這些容器時,就會出現問題。
      因此,在編寫程序時,必須要求程序員手動地在任何訪問到這些容器的地方進行同步處理,這樣導致在使用這些容器的時候非常地不方便。
      所以,Java提供了同步容器供用戶使用。
      二.Java中的同步容器類
      在Java中,同步容器主要包括2類:
      1)Vector、Stack、HashTable
      2)Collections類中提供的靜態工廠方法創建的類
      Vector實現了List接口,Vector實際上就是一個數組,和ArrayList類似,但是Vector中的方法都是synchronized方法,即進行了同步措施。
      Stack也是一個同步容器,它的方法也用synchronized進行了同步,它實際上是繼承于Vector類。
      HashTable實現了Map接口,它和HashMap很相似,但是HashTable進行了同步處理,而HashMap沒有。
      Collections類是一個工具提供類,注意,它和Collection不同,Collection是一個頂層的接口。在Collections類中提供了大量的方法,比如對集合或者容器進行排序、查找等操作。最重要的是,在它里面提供了幾個靜態工廠方法來創建同步容器類,如下圖所示:
      三.同步容器的缺陷
      從同步容器的具體實現源碼可知,同步容器中的方法采用了synchronized進行了同步,那么很顯然,這必然會影響到執行性能,另外,同步容器就一定是真正地完全線程安全嗎?不一定,這個在下面會講到。
      我們首先來看一下傳統的非同步容器和同步容器的性能差異,我們以ArrayList和Vector為例:
      1.性能問題
      我們先通過一個例子看一下Vector和ArrayList在插入數據時性能上的差異:
    public class Test {
    public static void main(String[] args) throws InterruptedException {
    ArrayList<Integer> list = new ArrayList<Integer>();
    Vector<Integer> vector = new Vector<Integer>();
    long start = System.currentTimeMillis();
    for(int i=0;i<100000;i++)
    list.add(i);
    long end = System.currentTimeMillis();
    System.out.println("ArrayList進行100000次插入操作耗時:"+(end-start)+"ms");
    start = System.currentTimeMillis();
    for(int i=0;i<100000;i++)
    vector.add(i);
    end = System.currentTimeMillis();
    System.out.println("Vector進行100000次插入操作耗時:"+(end-start)+"ms");
    }
    }
    這段代碼在我機器上跑出來的結果是:
      進行同樣多的插入操作,Vector的耗時是ArrayList的兩倍。
      這只是其中的一方面性能問題上的反映。
      另外,由于Vector中的add方法和get方法都進行了同步,因此,在有多個線程進行訪問時,如果多個線程都只是進行讀取操作,那么每個時刻就只能有一個線程進行讀取,其他線程便只能等待,這些線程必須競爭同一把鎖。
      因此為了解決同步容器的性能問題,在Java 1.5中提供了并發容器,位于java.util.concurrent目錄下,并發容器的相關知識將在下一篇文章中講述。
      2.同步容器真的是安全的嗎?
      也有有人認為Vector中的方法都進行了同步處理,那么一定就是線程安全的,事實上這可不一定。看下面這段代碼:
    public class Test {
    static Vector<Integer> vector = new Vector<Integer>();
    public static void main(String[] args) throws InterruptedException {
    while(true) {
    for(int i=0;i<10;i++)
    vector.add(i);
    Thread thread1 = new Thread(){
    public void run() {
    for(int i=0;i<vector.size();i++)
    vector.remove(i);
    };
    };
    Thread thread2 = new Thread(){
    public void run() {
    for(int i=0;i<vector.size();i++)
    vector.get(i);
    };
    };
    thread1.start();
    thread2.start();
    while(Thread.activeCount()>10)   {
    }
    }
    }
    }
      在我機器上運行的結果:
      正如大家所看到的,這段代碼報錯了:數組下標越界。
      也許有朋友會問:Vector是線程安全的,為什么還會報這個錯?很簡單,對于Vector,雖然能保證每一個時刻只能有一個線程訪問它,但是不排除這種可能:
      當某個線程在某個時刻執行這句時:
      for(int i=0;i<vector.size();i++)
      vector.get(i);
      假若此時vector的size方法返回的是10,i的值為9
      然后另外一個線程執行了這句:
      for(int i=0;i<vector.size();i++)
      vector.remove(i);
      將下標為9的元素刪除了。
      那么通過get方法訪問下標為9的元素肯定就會出問題了。
      因此為了保證線程安全,必須在方法調用端做額外的同步措施,如下面所示:
    public class Test {
    static Vector<Integer> vector = new Vector<Integer>();
    public static void main(String[] args) throws InterruptedException {
    while(true) {
    for(int i=0;i<10;i++)
    vector.add(i);
    Thread thread1 = new Thread(){
    public void run() {
    synchronized (Test.class) {   //進行額外的同步
    for(int i=0;i<vector.size();i++)
    vector.remove(i);
    }
    };
    };
    Thread thread2 = new Thread(){
    public void run() {
    synchronized (Test.class) {
    for(int i=0;i<vector.size();i++)
    vector.get(i);
    }
    };
    };
    thread1.start();
    thread2.start();
    while(Thread.activeCount()>10)   {
    }
    }
    }
    }
      3. ConcurrentModificationException異常
      在對Vector等容器并發地進行迭代修改時,會報ConcurrentModificationException異常,關于這個異常將會在后續文章中講述。
      但是在并發容器中不會出現這個問題。

    posted @ 2014-10-16 09:58 順其自然EVO 閱讀(202) | 評論 (0)編輯 收藏

    看我如何應對業務需求變化,“愚蠢”的應對?

    領域驅動設計的核心-Domain Model(領域模型),這個大家都知道,可是,上次關于領域模型的設計分享,要追溯到兩個月之前了,這中間搞了一些有的沒有的東西,比如糾結于倉儲等,說這些東西不重要,其實也蠻重要的,因為它是一個完整應用程序所必須要考慮的東西(Demo 除外),但是相對于領域模型,在領域驅動設計中它才是最重要的。
      這篇博文我分享的思路是:一個具體的業務場景,一個現實項目的業務需求變化,應用領域驅動設計,看我是如何應對的???
      注意:上面我用的是問號,所以,必不可少的會有一些“坑”,大家在讀的過程中,要“小心”哦。
      具體業務場景
      具體業務場景?沒錯,就是我們熟悉的博客園站內短消息,詳見:[網站公告]8月17日14:00-15:00(周日下午)發布新版站內短消息。
      上面那次版本發布,已經過去一個多月的時間了,說是“新版”,其實就是重寫之前短消息的代碼,然后用領域驅動設計的思想去實現,界面換了個“位置”,功能和原來的沒有太大變化。發布之后,出現了很多的問題,比如前端界面、數據庫優化、代碼不規范等等。有些技術問題可以很快的解決,比如數據庫的索引優化等,但是,有些問題,比如 SELECT FileName,因為程序代碼是基于領域驅動設計的思想去實現的,那你就不能直接去寫select filename1,filename2,filename2... from tablename這樣的 SQL 代碼,所以實現起來需要思考很多,這個是比較頭疼的。
      我為什么會說這些問題?因為這些問題,只有在實際應用項目中才會出現,你搞一個領域驅動設計的簡單 Demo,會出現數據庫性能問題嗎?肯定不會,那也就不會去思考倉儲的一些問題,更談不上一些改變了,所以領域驅動設計的推進,只有你去實際用它,而不只是做一些演示的東西,在實際應用中,去發現問題并解決問題,我覺得這樣才會更有價值。
      關于短消息這個業務場景,其實我之前寫的一些領域驅動設計博文,都是圍繞著它展開的,很多園友認為這個業務場景是我虛構的,就像之前 netfocus 兄問我:“你說的這個短消息是不是類似于博客園的短消息?”,我回答:“是的!”,呵呵。后來我發現虛構的業務場景,有時候很難說明問題,比如之前 Jesse Liu 在一篇博文中,提到一個用戶注冊問題,關于這個問題,其實討論了很久,但最后結果呢?我認為是沒有結果,因為業務場景是虛構的,所以就會造成“公說公有理,婆說婆有理”的情況,以至于大家很難達成一些共識的點。
      博客園短消息的業務場景,真實的不能再真實了,畢竟大家都在實際用,我就不多說了,就是簡單的一個用戶和另一個用戶發消息,然后進行回復什么的,在之前的一些博文中也有說明,大家可以參考下:我的“第一次”,就這樣沒了:DDD(領域驅動設計)理論結合實踐。
      業務需求變化
      現在的博客園短消息,為了方便用戶看到之前回復的一些內容,我們在底部增加了“=== 下面是回復信息 === ”,示意圖:
      這種方式其實就是把之前回復內容放到新消息內容里面,然后作為一個新消息進行發送,除去消息內容“冗余”不說,還有個弊端就是,如果兩個人回復的次數很多,你會發現,消息內容會變成“一坨XX”,不忍直視。
      后來,我們也看不下去了,所以決定做一些改變,仿照 iMessage 或 QQ 那種消息模式,示意圖:
      這種方式和上面那“一坨XX”形成了鮮明對比,對話模式的消息顯示,使用戶體驗度更好,就像兩個人面對面說話一樣,很輕松也很簡潔,我想我們這種方式的改變,會讓你“愛上”我們短消息的。
      對,沒錯,這就是業務需求變化,我們在應用程序開發的過程中,需求是一直不斷變化的,我們要做的就是不斷完善和適應這種需求變化,當然每個人應對的方式不同,下面看一下我“愚蠢”的應對。
     “愚蠢”的應對
      我個人覺得這一節點內容非常重要,在領域驅動設計的過程中,也是很多人常掉進的“坑”,因為我們長期受“腳本模式”的影響,在業務需求變化后,應用程序需要做出調整,但是你會不自覺的“跑偏”,這就偏離了領域驅動設計的思想,最后使你的應用程序變得“不倫不類”。
      當時為了很快的在應用程序中實現這種功能,我說的是技術上實現,完全沒有用領域驅動的思想去考慮,我是怎么思考的呢?先從 UI 上考慮,主要是兩個界面:
      消息列表:收件箱、發件箱和未讀消息列表。
      消息詳情:消息詳情頁。
      消息列表實現
      之前短消息不管發送,回復,還是轉發,都是作為一個新短消息進行發送的,“消息的上下文”作為一個消息的附屬體,放在新短息內容中,也就是說,你把之前發送的消息刪掉,在新回復的短消息內容中,是仍然看到之前發送內容的,這個在列表的顯示就是單獨進行顯示,但新的需求變化就不能這樣進行操作了,這個就有點像兩個人聊一個話題,里面都是我們針對這個話題進行討論的內容,在列表顯示的時候,首先,標題顯示就是這個話題的標題,就像郵件回復一樣,我們可以加上“消息標題(3)”,這個“3”,就表示兩個人回復了3次。
      其實用話題這個邏輯是有些不準確的,畢竟我們是短消息項目,我們可以這樣想,我給 netfocus 發了一個標題為:“打個招呼”,內容為:“hello netfocus”的消息,然后他給我進行了回復:“hello xishuai”,可能后面還有一些消息回復內容,但都是針對我發的第一條消息回復,也就是說下面都是回復內容,那這個在消息列表顯示的時候,標題就顯示為“打個招呼(3)”,后面時間為最新回復時間,示意圖:
      上面是 netfocus 的收件箱示意圖,收件箱列表顯示的邏輯就是以發件人和標題為一個標識,比如 Jesse Liu 也給 netfocus 發了一個“打個招呼”的消息,雖然標題一樣,但發件人不一樣,所以列表顯示兩條消息。
      那代碼怎么實現這個功能呢?貼出代碼看看:
      public async Task<IEnumerable<MessageListDTO>> GetInbox(Contact reader, PageQuery pageQuery)
      {
      var query = efContext.Context.Set<Message>()
      .Where(new InboxSpecification(reader).GetExpression()).GroupBy(m => new { m.Sender.ID, m.Title }).Select(m => m.OrderByDescending(order => order.ID).FirstOrDefault());
      int skip = (pageQuery.PageIndex - 1) * pageQuery.PageSize;
      int take = pageQuery.PageSize;
      return await query.SortByDescending(sp => sp.ID).Skip(skip).Take(take)
      .Project().To<MessageListDTO>().ToListAsync();//MessageListDTO 為上一版本遺留問題(Select FileName),暫時沒動。
      }
      GetInbox 是 MessageRepository 中的操作,其實原本收件箱的代碼不是這樣處理的,你會看到,現在的代碼其實就是 Linq 的代碼拼接,我當時這樣處理就是為了可以方便查詢,現在看確實像“一坨XX”,代碼我就不多說了,上面列表顯示功能是可以實現的,除去回復數顯示,其實你會看到,這個就是對發件人和標題進行篩選,選取發送時間最新的那一條消息。
      雖然這段 Linq 代碼看起來很“簡單”,但是如果你跟蹤一下生成的 SQL 代碼,會發現它是非常的臃腫,沒辦法,為了實現功能,然后就不得不去優化數據庫,主要是對索引的優化,這個當時優化了好久,也沒有找到合適的優化方案,最后不得不重新思考這樣做是不是不合理?這完全是技術驅動啊,后來,我發現,在領域驅動設計的道路上,我已經完全“跑偏”了。
      消息詳情頁實現
      業務需求的變化,其實主要是消息詳情頁的變化,從上面那張消息詳情頁示意圖就可以看出,剛才上面說了,收件箱列表顯示是對標題和發件人的篩選,其實詳情頁就是通過標題和發件人找出回復消息,然后通過發送時間降序排列。具體操作是,在收件箱中點擊一條消息,然后通過這條消息和發件人去倉儲中找這條消息的回復消息,示例代碼:
      public async Task<IEnumerable<Message>> GetMessages(Message message, Contact reader)
      {
      if (message.Recipient.ID == reader.ID)
      {
      return await GetAll(Specification<Message>.Eval(m => m.Title == message.Title
      && ((m.Sender.ID == message.Sender.ID && m.Recipient.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Inbox))
      || (m.Recipient.ID == message.Sender.ID && m.Sender.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Outbox)))),
      sp => sp.ID, SortOrder.Ascending).ToListAsync();
      }
      else
      {
      return await GetAll(Specification<Message>.Eval(m => m.Title == message.Title
      && ((m.Sender.ID == message.Sender.ID && m.Recipient.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Outbox))
      || (m.Recipient.ID == message.Sender.ID && m.Sender.ID == message.Recipient.ID && (m.DisplayType == MessageDisplayType.OutboxAndInbox || m.DisplayType == MessageDisplayType.Inbox)))),
      sp => sp.ID, SortOrder.Ascending).ToListAsync();
      }
      }
      不知道你是否能看懂,反正我現在看這段代碼是需要思考一下的,呵呵。消息詳情頁基本上就是這樣實現的,還有一些是在應用層獲取“點擊消息”,UI 中消息顯示判斷等一些操作。
    消息發送、回復、銷毀等實現
      其實除了上面列表和詳情頁的變化,消息發送、回復和銷毀實現也需要做出調整,因為消息領域模型沒有任何變動,發送消息還是按照之前的發送邏輯,所以發送消息是沒有變化的,回復消息也沒有大的變化,只不過回復的時候需要獲取一下消息標題,因為除了第一條發送消息需要填寫標題,之后的消息回復是不需要填寫標題的,需要添加的只不過是消息內容。消息銷毀的改動相對來說大一點,因為之前都是獨立的消息發送,所以可以對每個獨立的消息進行銷毀操作,但是從上面消息詳情頁示意圖中可以看到,獨立的消息是不能銷毀的,只能銷毀這個完整的消息,也就是詳情頁最下面的刪除按鈕,示例代碼:
      public async Task<OperationResponse> DeleteMessage(int messageId, string readerLoginName)
      {
      IContactRepository contactRepository = new ContactRepository();
      IMessageRepository messageRepository = new MessageRepository();
      Message message = await messageRepository.GetByKey(messageId);
      if (message == null)
      {
      return OperationResponse.Error("抱歉!獲取失敗!錯誤:消息不存在");
      }
      Contact reader = await contactRepository.GetContactByLoginName(readerLoginName);
      if (reader == null)
      {
      return OperationResponse.Error("抱歉!刪除失敗!錯誤:操作人不存在");
      }
      if (!message.CanRead(reader))
      {
      throw new Exception("抱歉!獲取失敗!錯誤:沒有權限刪除");
      }
      message.DisposeMessage(reader);
      var messages = await messageRepository.GetMessages(message, reader);
      foreach (Message item in messages)
      {
      item.DisposeMessage(reader);
      messageRepository.Update(item);
      }
      await messageRepository.Context.Commit();
      return OperationResponse.Success("刪除成功");
      }
      這個是應用層中消息銷毀操作,可以看到應用層的這個操作代碼很凌亂,這就是為了實現而實現的代價,除了消息銷毀,還有一個操作就是消息狀態設置,也就是消息“未讀”和“已讀”設置,這個代碼實現在應用層 ReadMessage 操作中,代碼更加凌亂,我就不貼出來了,和消息銷毀操作比較類似,消息狀態設置只不過設置一些狀態而已。
      回到原點的一些思考
      為什么我會詳細描述我當時實現的思路?其實就是想讓你和我產生一些共鳴,上面的一些實現操作,完全是為了實現而實現,不同的應用場景下的業務需求變化是不同的,但思考的方式一般都是想通的,也就是說如果你能正確應對這個業務需求變化,那換一個應用場景,你照樣可以應對,如果你不能正確應對,那領域驅動設計就是“空頭白話”,為什么?因為領域驅動設計就是更好的應對業務需求變化的。
      其實上面的需求變化,我們已經變相的實現了,只不過沒有發布出來,就像一個多月之前的發布公告中所說,“Does your code look like this?”,如果按照這種方式實現了,那以后的短消息代碼,就是那一坨面條,慘不忍睹。
      回到原點的一些思考,其實就是回到領域模型去看待這次的業務需求變化,關于這部分內容,我還沒有準確的做法,這邊我說一下自己的理解:
      業務需求變化,領域模型變化了嗎?
      首先,在之前的實現中,消息列表顯示這部分內容,應該是應用層中體現的,所以在領域模型中可以暫時不考慮,這個在倉儲中應該著重思考下。那領域模型變化了什么?先說發送消息,這個變化了嗎?我覺得沒有,還是點對點的發送一個消息,這個之前是用 SendSiteMessageService 領域服務實現的,邏輯也沒有太大的變化,那回復消息呢?其實我覺得這是最大的一個變化,如果你看之前的回復代碼,我是沒有在領域模型中實現回復消息操作的,為什么?因為我當時認為,回復消息其實也是發送消息,所以在應用層中回復消息操作,其實就是調用的 SendSiteMessageService 領域服務,這個現在看來,是不應該這樣實現的。
      我們先梳理一下回復消息這個操作的處理流程,這個其實上面有過分析,除了第一條消息是發送以外,之后的消息都是回復操作,這就要有一個標識,用來說明這條消息是回復的那一條發送消息,那這個怎么來設計呢?回復消息設計成實體好?還是值對象好?我個人覺得,應該設計成實體,原因大家想想就知道了,雖然它依附于發送消息存在,但是它也是唯一的,比如一個人給另外兩個人回復同樣內容的消息,那這兩個回復消息應該都是獨立存在的,那這個依附關系怎么處理呢?我們可以在消息實體中添加一個標識,用來表示它回復的是那條消息。
      上面這個確定之后,那我們如何實現回復消息操作呢?我們可以用一個領域服務實現,比如 ReplySiteMessageService,用來處理回復消息的一些操作,這個和 SendSiteMessageService 領域服務可能會有些不同,比如一個人 1 天只能發送 200 條消息,但是這個邏輯我們就不能放在回復消息領域服務中,回復只是針對一個人的回復,所以這個可以不做限制,發送是針對任何人的,為了避免廣告推廣,這個我們必須要做一個發送限制,當然具體實現,就要看需求的要求了。
      除了回復消息這個變化,說多一點,消息狀態(未讀和已讀)和消息銷毀,這個可能也會有細微的變化,比如消息狀態,在消息列表中打開一個消息,其實就是把這條消息的回復內容都設置成已讀了,我們之前的設計是針對獨立的消息狀態,也就是說每個消息都有一個消息狀態,按照這種方式,其實我們可以把這個狀態放在發送消息實體中,如果有人回復了,那這個消息狀態就是設置為未讀,回復消息沒有任何狀態,如果這樣設計的話,有點像值對象的感覺,可以從消息實體中獨立出來一個回復消息值對象,當然這只是我的一種思路。消息銷毀和這個消息狀態比較類似,這邊就不多說了,除了這兩個變化,其實還有一些細節需要考慮,這個只能在實現中進行暴露出來了。
      對象讀取的額外思考
      這個其實是我看了倉儲那慘不忍睹的實現代碼,所引起的一些思考,你可以讀一下,這樣的一篇博文:你正在以錯誤的方式使用ORM。
      倉儲在領域驅動設計的作用,可以看作是實體的存儲倉庫,我們獲取實體對象就要經過倉儲,倉儲的實現可以是任何方式,但傳輸對象必須是聚合根對象,這個在理論中沒有什么問題,但是在實際項目中,我們從倉儲中獲取對象,一般有兩種用途:
      用于領域模型中的一些驗證操作。
      用于應用層中的 DTO 對象轉化。
      第一種沒有什么問題,但是第二種,這個就不可避免的造成性能問題,也就是上面文中 Jimmy(AutoMapper 作者)所說的 Select N 問題,這個我之前也遇到過,最后的解決方式,我是按照他在 AutoMapper 映射的一些擴展,也就是上面代碼中的 Project().To(),但這樣就不可避免的違背了領域驅動設計中倉儲的一些思想。
      關于這個內容,我不想說太多,重點是上面領域模型的思考,倉儲的問題,我是一定要做一些改變的,因為它現在的實現,讓強迫癥的我感覺到非常不爽,不管是 CQRS、ES、還是六邊形架構,總歸先嘗試實現再說,有問題不可怕,可怕的是不懂得改正。
      寫在最后
      在領域驅動設計的道路上,有很多你意想不到的情況發生,稍微不注意,你就會偏離的大方向,很遺憾,我沒有針對這次的業務需求變化,做出一些具體的實現,但我覺得意識到問題很重要,這篇博文分享希望能與你產生一些共鳴。

    posted @ 2014-10-16 09:56 順其自然EVO 閱讀(209) | 評論 (0)編輯 收藏

    TP-四種url訪問的方式

    1:http://localhost/index.php?m=模塊&c=控制器&a=操作方法     [get模式]
    2:http://localhost/index.php/模塊[模塊文件夾]/控制器/操作方法    [pathinfo模式]
    3:http://localhost/模塊[模塊文件夾]/控制器/操作方法     [rewite重寫模式]
    4:http://localhost/index.php?s=/模塊[模塊文件夾]/控制器/操作方法  [兼容模式]
    具體的url模式 在ThinkPHP/conf/convention.php文件下
    大概在138行    默認的是pathinfo模式
    'URL_MODEL' => 1, // URL訪問模式,可選參數0、1、2、3,代表以下四種模式:
    // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE 模式); 3 (兼容模式)    默認為PATHINFO 模式
    5:具體修改訪問模式如下:
    config.php是我們當前自己的項目配置文件,我們可以通過修改文件達到配置變量的目錄,
    這個文件在系統運行過程中會覆蓋convertion.php的配置變量
    因為:我們在新建控制的器的時候需要引入
    include 'convertiion.php';
    include 'config.php'
    后引入的文件會把先引入的文件中的配置給覆蓋掉~
    配置如下:
    <?php
    return array(
    //'配置項'=>'配置值'
    //配置URL模式
    'URL_MODEL'=>0    //默認的為1 所以現在改為第一種get模式。
    );
      //把目前的tp框架的生成模式改變成為開發模式
      define("APP_DEBUG", true);
      快捷函數 U();
      使用方法如下:  U("模塊/控制器/方法")    根據url模式來生成地址!
      開發調試模式:系統要加載26文件
      生成模式:系統只要加載很少的文件。
      查看系統運行日志:可知道系統加載了多少文件

    posted @ 2014-10-16 09:53 順其自然EVO 閱讀(6689) | 評論 (0)編輯 收藏

    可用性測試之發聲思考

    定義發聲思考測試
      定義:在一個發聲思考測試中,測試的參與者在執行任務行為時實時的說出自己腦子中所想的內容
      這看上去是一個很簡單的要求,但是在實際過程中要求一個測試者不停地說出自己所想是非常困難的,所以測試的實施者必須不斷的提醒測試者。
      進行一個基本的發聲思考可用性測試,只需要做3件事情
      招募代表性用戶
      讓他們執行有代表性的任務
      閉上嘴聽測試用戶說
      發聲的好處
      首先這個方法有一大堆優勢。其中最重要的是,發聲為想法提供了一個可見的窗口,透過窗口你可以發現用戶到底是如何使用和看待你的設計的。特別的,你可以發現他們產生誤解的地方,這些往往是需要進行重新設計的,所有引起誤解的元素都必須改變。更重要的是,你可以從中發現為什么用戶會產生誤解,為什么其他的設計方式會更易用。
      發聲的好處還有
      低花費。不需要特殊的儀器,只需要你坐在測試對象旁邊記錄他所說的話。收集到足夠多數量的用戶測試信息可能會花費一整天的時間,但這一定是值得的
      可信度高。大多數的實驗者都缺乏經驗所以大多數時候測試都不能夠按照最正確的方式進行。但是除非你嚴重干涉誤導測試者,即使在不標準的測試中你依然能夠獲得大量有價值的發現。相比之下,定量的可用性研究對于方法的精確度要求的更加嚴格,很小的錯誤也可能導致研究結果出現巨大偏差。定量的研究往往也花費更高。
      靈活度高。在開發的任意時期你都可以進行這樣的測試,從紙上的原型到已經成型的原型。發聲思考特別適合敏捷式的開發模式。你可以運用這種方法測試任意形式的用戶界面,雖然用發聲的方式測試聲音交互界面有點奇怪,但是你可以參考這篇文章里關于進行有實力測試障礙的人的測試。不論是網站,軟件,局域網,消費類產品,企業級軟件,移動設計,發聲測試都可以運用,因為他只依賴于可以思考的用戶
      有說服力。最老練的開發者,傲慢的設計師,吝嗇的總經理在直接面對消費者的時候態度都會變得溫和。讓他們坐下來聽聽在發聲測試中用戶的想法并不會花費他們太多的時間,并且有可能促使他們重視可用性。
      簡單易懂。
      發聲思考的問題
      花費低和不容易出錯是定性研究方法諸如發聲思考的巨大優勢。但他們不好的一面是除非你進行的是一個巨大昂貴的實驗,否則是不能形成定量數據的。當然你可以選擇做一個巨大昂貴的實驗,但是我的建議是這些精力和經費投資在更多的設計迭代過程中更值得。
      其他問題
      不自然。除非測試者是個怪人,大多數普通人不會坐在那里自言自語一整天。所以想要讓測試者在測試過程中保持自言自語其實是一個比較困難的過程。幸運的是來參加測試的人一般都會比較積極的配合,以至于有時可能忘記自己僅僅是在進行一項測試。
      想法過濾。測試者被要求說出他們腦中呈現的第一印象,而不是說出經過了思考之后的分析結果。但是與此同時,大多數人希望自己表現的像個聰明人,于是他們更傾向于在說出自己所想之前先思考一番。千萬不要陷入了這個陷阱,獲得測試用戶最原始的想法是非常重要的。所以一般情況下,實驗者必須不斷的提醒用戶不斷的說。
      誤導用戶行為。指導和解釋說明在測試過程中是必要的,但假如是一個不專業的實驗者來進行,那么他給予的信息很可能會改變用戶原本的行為。有誤導存在的情況下,用戶的行為是沒有代表性的,更無法提供設計依據。至少,你必須能夠識別出在哪些測試中用戶的行為是被誤導了的,作廢這些觀測結果。最糟糕的情況就是你不知道自己在哪些地方做錯了,這樣你提供給設計團隊的意見很有可能就是錯誤的
      不一定通用。只要你同時使用其他的方法,不通用事實上并不是一個真正的缺點。發聲思考可以在大多數情況下使用,但也并非全部情況下通用。一旦你在可用性測試這方面有了一定的經驗,你會有其他很多測試方法可以選擇
      不要因為這些問題就退縮,如果你還沒有使用過這個方法,你可以現在就為自己正在進行的設計項目進行一次。這個方法是如此的簡單易行,每周一次都是完全可行的。所以如果你這一周犯了錯誤,下一周你一定可以做的更好。

    posted @ 2014-10-16 09:50 順其自然EVO 閱讀(185) | 評論 (0)編輯 收藏

    Android如何進行單元測試

     Menifest.xml中加入:
    <application>中加入:
    <uses-library android:name="android.test.runner" />
    <application>外面加入:
    <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" />
    <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="name.feisky.android.test"
    android:label="Test for my app"/>
      編寫單元測試代碼:必須繼承自AndroidTestCase類
    package name.feisky.android.test;
    import android.test.AndroidTestCase;
    import junit.framework.Assert;
    public class MyTest extends AndroidTestCase {
    private static final String Tag="MyTest";
    }

    posted @ 2014-10-16 09:50 順其自然EVO 閱讀(283) | 評論 (0)編輯 收藏

    用路徑分析法來編寫測試用例

    熟悉測試理論的人都知道,路徑覆蓋是白盒測試中一種很重要的方法,廣泛應用于單元測試。那么基于路徑覆蓋的分析方法是不是只能應用于單元測試呢,能不能將其推而廣之呢。一般而言,在單元測試中,路徑就是指函數代碼的某個分支,而實際上如果我們將軟件系統的某個流程也看成路徑的話,我們將可以嘗試著用路徑分析的方法來設計測試用例。采用路徑分析的方法設計測試用例有兩點好處:一是降低了測試用例設計的難度,只要搞清了各種流程,就可以設計出高質量的測試用例來,而不用太多測試方面的經驗;二是在測試時間較緊的情況下,可以有的放矢的選擇測試用例,而不用完全根據經驗來取舍。下面就具體的介紹一下如何用路徑分析的方法編寫測試用例。
      首先是將系統運行過程中所涉及到的各種流程圖表化,可以先從最基本的流程入手,將流程抽象成為不同功能的順序執行。在最基本流程的基礎上再去考慮次要或者異常的流程,這樣將各種流程逐漸細化,這樣既可以逐漸加深對流程的理解,還可以將各個看似孤立的流程關聯起來。完成所有流程的圖表化后就完成了所有路徑的設定。
      找出了所有的路徑,下面的工作就是給每條路徑設定優先級,這樣在測試時就可以先測優先級高的,再測優先級低的,在時間緊迫的情況下甚至可以考慮忽略一些低優先級的路徑。優先級根據兩個原則來選取:一是路徑使用的頻率,使用越頻繁的優先級越高;二是路徑的重要程度,如果失敗對系統影響越大的優先級越高。將根據兩個原則所分別得到的優先級相加就得到了整個路徑的優先級。根據優先級的排序就可以更有針對性的進行測試。
      為每條路徑設定好優先級后,接下來的工作就是為每條路徑選取測試數據,構造測試用例。一條路徑可以對應多個測試用例,在選取測試數據時,可以充分利用邊界值選取等方法,通過表格將各種測試數據的輸入輸出對應起來,這樣就完成了測試用例的設計。
      對于測試人員而言,測試用例的設計是一件非常困難的工作,而同時測試用例的設計好壞又直接關系到整個系統的設計質量。本文介紹了一種更理論化的設計方法來盡量簡化這種工作,將一般應用于單元測試的路徑分析方法推廣到集成測試、系統測試等后續測試過程中,希望能給大家一點啟示。我會將自己嘗試過的一些感受以及具體例子跟在本貼之后。
      如果想讓本方法很好的用在實際的工作中,那么流程就必須明確的規范的(就是有畫出相應業務或者功能走向圖),這樣就可以極大的加快了用例編寫的速度和質量,但是如果碰到沒有明確流程圖的時候,可能會花不少的時間去捉摸功能點的流程走向問題,這又讓工作進度慢了下來(流程不明確是因為需求沒有明確表述和設計沒有相應流程描述),所以在實際工作中想使用這種方法來加快和改進測試用例的進度和質量,還要說服項目組盡可能的規范需求和設計的文檔規范性,畢竟軟件質量的控制不是我們一組人就能做到的。
      拿到這個流程時,第一眼看上去,是不是有點暈暈的呢,確實如此,因為這不能稱為標準的流程圖,我們需要做一些改進,不妨事先約定,畫流程圖時,在有判定條件處,就往下走,而就往左走,以下是簡化后的流程:
    上面這個流程圖看上去是不是清晰很多,確實如此,從心理學的角度來講,正常人的思維是很難接受一個橫向很復雜的事物。而且上面的流程圖也更規范一點,所以建議大家以后這樣畫流程圖。下圖是作進一步的改進:這個流程圖是不是更方便你設計用例呢,尤其是用路徑分析法,是不是很方便就能找出其中的路徑。
      這個流程圖是不是更方便你設計用例呢!尤其是用路徑分析法,是不是很方便就能找出其中的路徑。

    posted @ 2014-10-16 09:47 順其自然EVO 閱讀(227) | 評論 (0)編輯 收藏

    《我所知道的軟件測試自動化》- 關鍵字驅動的過去和未來

         摘要: 鑒于cnblogs的排版問題,PDF格式下載點擊這里。關鍵字驅動的過去和未來.pdf  版權聲明:本文可以被轉載,但是在未經本人許可前,不得用于任何商業用途或其他以盈利為目的的用途。本人保留對本文的一切權利。如需轉載,請在轉載是保留此版權聲明,并保證本文的完整性。也請轉貼者理解創作的辛勞,尊重作者的勞動成果。作者:陳雷 (Jackei)Blog:http://jack...  閱讀全文

    posted @ 2014-10-16 09:43 順其自然EVO 閱讀(641) | 評論 (0)編輯 收藏

    Linux下DB2數據庫安裝教程

    最近因為工作需要在學習DB2數據庫,本教程講解DB2數據庫在inux下的安裝步驟。
      安裝前請查看 DB2版本和許可證 說明來增加了解,先弄明白改安裝什么版本,這里我用的是最新的Express-C版本,這個版本是提供給個人學習用的版本。
      管理客戶端從v9.7版本之后就不再帶有控制中心了,而是使用 Data Studio Client。
      Linux版本:
      Linux版本下的DB2數據庫采用的官方免費版本,操作系統用的CentOS6.2。
      安裝過程:
      1、下載:db2_v101_linuxia32_expc.tar.gz
      2、解壓,解壓完成后會在當前目錄下有一個 ./expc 文件夾
      [root@localhost opt]# tar -zxvf db2_v101_linuxia32_expc.tar.gz
      發布地址: http://www.cnblogs.com/zxlovenet/p/3972766.html
      3、進入這個目錄
      [root@localhost opt]# cd expc/
      4、執行安裝
      [root@localhost expc]# ./db2_install
      5、添加組和用戶:
      組(用戶名)
    db2iadm1(db2inst1)
    db2fadm1( db2fenc1)
    [root@localhost expc]# groupadd -g 2000 db2iadm1
    [root@localhost expc]# groupadd -g 2001 db2fadm1
    [root@localhost expc]# useradd -m -g db2iadm1 -d /home/db2inst1 db2inst1
    [root@localhost expc]# useradd -m -g db2fadm1 -d /home/db2fenc1 db2fenc1
    [root@localhost expc]# passwd db2inst1
    [root@localhost expc]# passwd db2fenc1
      6、安裝 license(產品許可證) PS:如果是ExpressC版本就不用做
      [root@localhost adm]# pwd
      /opt/ibm/db2/V10.1/adm
      [root@localhost adm]# chmod -R 775 *
      [db2inst1@localhost adm]$ ./db2licm -a /tmp/seagull/db2v10/license/db2ese_c.lic
      7、創建實例和樣本數據庫
    [root@localhost instance]# pwd
    /opt/ibm/db2/V10.1/instance
    [root@localhost instance]# chmod -R 775 *
    [root@localhost instance]# ./db2icrt -p 50000 -u db2fenc1 db2inst1
    [root@localhost instance]# su - db2inst1
    [db2inst1@localhost ~]$ db2sampl
    Creating database "SAMPLE"...
    Connecting to database "SAMPLE"...
    Creating tables and data in schema "DB2INST1"...
    Creating tables with XML columns and XML data in schema "DB2INST1"...
    'db2sampl' processing complete.
    [db2inst1@localhost ~]$ db2start
    SQL1026N The database manager is already active.
    [db2inst1@localhost ~]$ db2 connect to sample
    Database Connection Information
    Database server = DB2/LINUX 10.1.2
    SQL authorization ID = DB2INST1
    Local database alias = SAMPLE
    [db2inst1@localhost ~]$ db2 "select * from staff"
     8、創建 das 管理服務器
      為了遠程客戶端能夠用控制中心來控制數據庫服務器,需要在數據庫服務器上安裝 das,當然,如果只是遠程連接而不是遠程管理,可以不用裝,這里我安裝了一下。
    [root@localhost expc]# groupadd -g 2002 db2asgrp
    [root@localhost expc]# useradd -m -g db2asgrp -d /home/db2as db2as
    [root@localhost expc]# passwd db2as
    [db2as@localhost ~]$ su - db2as # 這里測試新建用戶
    [db2as@localhost ~]$ su # 這里進入root權限
    [root@localhost ~]# cd /opt/ibm/db2/V10.1/instance/
    [root@localhost instance]# ./dascrt -u db2as
    DBI1070I Program dascrt completed successfully.
    [root@localhost instance]# su - db2as
    [db2as@localhost ~]$ db2admin start
    SQL4409W The DB2 Administration Server is already active.
      9、設置端口號
      vim /etc/services
      在最后增加一行 # PS:VIM快捷鍵,在命令模式下輸入“G”跳刀最后一行。
      db2inst1 50000/tcp
      10、db2 配置,要切換到用戶 db2inst1
      su - db2inst1
      db2set DB2_EXTENDED_OPTIMIZATION=ON
      db2set DB2_DISABLE_FLUSH_LOG=ON
      db2set AUTOSTART=YES
      db2set DB2_STRIPED_CONTAINERS=ON
      db2set DB2_HASH_JOIN=Y
      db2set DB2COMM=tcpip
      db2set DB2_PARALLEL_IO=*
      db2set DB2CODEPAGE=819 # PS:這個地方比較重要
      # db2 update database manager configuration using svcename db2inst1
      11.將SVCENAME設置成/etc/services中的端口號或者服務名了嗎?
      [db2inst1@localhost ~]$ db2 get dbm cfg|grep SVCENAME
      TCP/IP Service name (SVCENAME) =
      SSL service name (SSL_SVCENAME) =
      發布地址: http://www.cnblogs.com/zxlovenet/p/3972766.html
      找到SVCENAME,如果當前值不是服務器端的端口號或者服務名,進行更新設置。
      [db2inst1@localhost ~]$ db2 update dbm cfg using SVCENAME db2inst1
      # db2 update dbm cfg using INDEXREC ACCESS
      [db2inst1@localhost ~]$ db2 get dbm cfg|grep SVCENAME
      TCP/IP Service name (SVCENAME) = 50000
      SSL service name (SSL_SVCENAME) =
      # PS:svcename 在客戶端連接時需要用到
      12.在啟動DB2之前需要先關閉防火墻,不然的話根本就不能連接(這個地方的疏忽糾結了好久),在root用戶下執行:service iptables stop
      13.開啟DB2,執行:db2start ,如果已經開啟狀態,那就先停止,執行:db2stop 。
      PS:參考鏈接如下
      http://www.db2china.net/home/space.php?uid=92501&do=blog&id=25771
      http://blog.csdn.net/xiaolang85/article/details/3887459
      設置查看:
      PS:重啟機器后遇到了一個問題,就是關閉防火墻無反應,開啟關閉數據庫無反應,遠程不能連接到數據庫,解決辦法是重啟了服務器,然后按照順序關閉了防火墻,然后重啟了DB2數據庫。

    posted @ 2014-10-15 09:57 順其自然EVO 閱讀(1499) | 評論 (1)編輯 收藏

    僅列出標題
    共394頁: First 上一頁 32 33 34 35 36 37 38 39 40 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 黄瓜视频影院在线观看免费| 亚洲AV综合色区无码二区爱AV| 成人免费在线视频| 久久青草国产免费观看| 搜日本一区二区三区免费高清视频| 国产成人精品日本亚洲专区6| 国产成A人亚洲精V品无码| 国产成人亚洲精品影院| 性色av免费观看| 99久久99久久精品免费看蜜桃| 麻豆精品不卡国产免费看| 一级做a爰片性色毛片免费网站 | 五月天婷婷免费视频| 亚洲中文字幕乱码AV波多JI| 久久精品九九亚洲精品| 野花视频在线官网免费1| 国产91在线|亚洲| 亚洲系列中文字幕| 亚洲精选在线观看| 亚洲成a人片在线观看无码| 国产AV无码专区亚洲AV手机麻豆| 无码欧精品亚洲日韩一区夜夜嗨| 毛片a级毛片免费观看免下载| 91短视频免费在线观看| 无码免费一区二区三区免费播放| 国产在线观看xxxx免费| 国产免费黄色无码视频| xxxxx做受大片视频免费| 高潮毛片无遮挡高清免费| 色五月五月丁香亚洲综合网| 久久精品国产亚洲av天美18| 国产亚洲精品AAAA片APP| 国产亚洲欧美在线观看| 黄色片网站在线免费观看| 黄色免费网址在线观看| 免费国产污网站在线观看不要卡| 一区二区三区免费在线视频| 一级毛片人与动免费观看| 精品国产污污免费网站入口| 中文在线观看永久免费| 久久er国产精品免费观看2|