qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          Oracle數(shù)據(jù)庫的DML命令的處理過程詳解

            Oracle數(shù)據(jù)庫的DML命令的處理過程是本文我們主要要介紹的內(nèi)容,從Oracle 9i起,有兩種undo的管理方式:自動Undo管理(Automatic Undo Management,簡稱AUM)和手工Undo管理(Manual Undo Management,簡稱MUM)。Oracle 9i之前只能使用MUM,而且在MUM中,undo segment又叫做rollback segment。從Oracle 9i起,Oracle就建議使用AUM,而不應(yīng)再使用MUM了。

            DML語句與undo

            當(dāng)我們發(fā)出一條DML(比如update tab set col1='A' where col1='B')語句時,其執(zhí)行過程可大致概括為以下幾步。

            1、在shared pool里進(jìn)行解析,從而生成執(zhí)行計劃。

            2、假設(shè)根據(jù)執(zhí)行計劃,得出col1='B'的記錄存放在10號數(shù)據(jù)文件的54號數(shù)據(jù)塊里。

            3、服務(wù)器進(jìn)程在buffer cache里找一個可用的undo數(shù)據(jù)塊,如果沒有發(fā)現(xiàn),則到undo表空間里找一個可用的undo塊,并調(diào)入buffer cache。假設(shè)獲得的undo數(shù)據(jù)塊號為24號,位于11號undo數(shù)據(jù)文件里。

            4、將改變前的值,也就是A放入11號undo數(shù)據(jù)塊。

            5、由于undo數(shù)據(jù)塊發(fā)生了變化,于是產(chǎn)生重做記錄,假設(shè)重做記錄號為120。

            行號 事務(wù)id file# block# row column value

            120 T1 24 11 10 col1 A

            6、在buffer cache里找到54號數(shù)據(jù)塊。如果沒有發(fā)現(xiàn),則從10號數(shù)據(jù)文件里調(diào)入。

            7、將改變后的值,也就是B放入54號數(shù)據(jù)塊。

            8、由于數(shù)據(jù)塊發(fā)生了變化,于是產(chǎn)生重做記錄,假設(shè)重做記錄號為121。

            行號 事務(wù)id file# block# row column value

            121 T1 10 54 10 col1 B

            9、控制權(quán)返回給用戶,如果在SQL*Plus里執(zhí)行DML,則表現(xiàn)為光標(biāo)返回。

            10、當(dāng)用戶發(fā)出commit命令時,觸發(fā)LGWR進(jìn)程,將120與121這兩個重做記錄寫入聯(lián)機(jī)日志文件,并將54號數(shù)據(jù)塊和11號undo數(shù)據(jù)塊頭部所記錄的事務(wù)狀態(tài)標(biāo)記設(shè)置為已提交。然后控制權(quán)返回給用戶,如果在SQL*Plus里執(zhí)行DML操作,則表現(xiàn)為光標(biāo)返回。

            11、這個時候,54號數(shù)據(jù)塊以及11號undo塊并不一定被DBWn寫入數(shù)據(jù)文件。只有在臟數(shù)據(jù)塊的數(shù)量達(dá)到一定程度才會被寫入。

            事務(wù)只要被提交或回滾,那么該事務(wù)所使用的undo塊就可以被覆蓋。對于上面的例子來說,當(dāng)?shù)?0步,用戶發(fā)出commit命令以后,11號undo塊里的數(shù)據(jù)就可以被其他事務(wù)所覆蓋。

            關(guān)于Oracle數(shù)據(jù)庫的DML命令的處理過程的相關(guān)知識就介紹到這里了,希望本次的介紹能夠?qū)δ兴斋@!

          posted @ 2012-05-14 09:57 順其自然EVO 閱讀(186) | 評論 (0)編輯 收藏

          Java調(diào)用SQL Server的存儲過程詳解

           1、使用不帶參數(shù)的存儲過程

            使用 JDBC 驅(qū)動程序調(diào)用不帶參數(shù)的存儲過程時,必須使用 call SQL 轉(zhuǎn)義序列。不帶參數(shù)的 call 轉(zhuǎn)義序列的語法如下所示:

          {call procedure-name}

            作為實例,在 SQL Server 2005 AdventureWorks 示例數(shù)據(jù)庫中創(chuàng)建以下存儲過程:

          1. CREATE PROCEDURE GetContactFormalNames  
          2. AS 
          3. BEGIN 
          4.  SELECT TOP 10 Title + ' ' + FirstName + ' ' + LastName AS FormalName  
          5.  FROM Person.Contact  
          6. END

            此存儲過程返回單個結(jié)果集,其中包含一列數(shù)據(jù)(由 Person.Contact 表中前十個聯(lián)系人的稱呼、名稱和姓氏組成)。

            在下面的實例中,將向此函數(shù)傳遞 AdventureWorks 示例數(shù)據(jù)庫的打開連接,然后使用 executeQuery 方法調(diào)用 GetContactFormalNames 存儲過程。

          1. public static void executeSprocNoParams(Connection con) ...{  
          2.  try ...{  
          3.  Statement stmt = con.createStatement();  
          4. ResultSet rs = stmt.executeQuery("{call dbo.GetContactFormalNames}");  
          5.  while (rs.next()) ...{  
          6.  System.out.println(rs.getString("FormalName"));  
          7. }  
          8. rs.close();  
          9. stmt.close();  
          10.   }  
          11. catch (Exception e) ...{  
          12. e.printStackTrace();  
          13. }  
          14. }

            2、使用帶有輸入?yún)?shù)的存儲過程

            使用 JDBC 驅(qū)動程序調(diào)用帶參數(shù)的存儲過程時,必須結(jié)合 SQLServerConnection 類的 prepareCall 方法使用 call SQL 轉(zhuǎn)義序列。帶有 IN 參數(shù)的 call 轉(zhuǎn)義序列的語法如下所示:

          {call procedure-name[([parameter][,[parameter]]...)]}

            構(gòu)造 call 轉(zhuǎn)義序列時,請使用 ?(問號)字符來指定 IN 參數(shù)。此字符充當(dāng)要傳遞給該存儲過程的參數(shù)值的占位符。可以使用 SQLServerPreparedStatement 類的 setter 方法之一為參數(shù)指定值。可使用的 setter 方法由 IN 參數(shù)的數(shù)據(jù)類型決定。

            向 setter 方法傳遞值時,不僅需要指定要在參數(shù)中使用的實際值,還必須指定參數(shù)在存儲過程中的序數(shù)位置。例如,如果存儲過程包含單個 IN 參數(shù),則其序數(shù)值為 1。如果存儲過程包含兩個參數(shù),則第一個序數(shù)值為 1,第二個序數(shù)值為 2。

            作為如何調(diào)用包含 IN 參數(shù)的存儲過程的實例,使用 SQL Server 2005 AdventureWorks 示例數(shù)據(jù)庫中的 uspGetEmployeeManagers 存儲過程。此存儲過程接受名為 EmployeeID 的單個輸入?yún)?shù)(它是一個整數(shù)值),然后基于指定的 EmployeeID 返回雇員及其經(jīng)理的遞歸列表。下面是調(diào)用此存儲過程的 Java 代碼:

          1. public static void executeSprocInParams(Connection con) ...{  
          2.  try ...{  
          3.  PreparedStatement pstmt = con.prepareStatement("{call dbo.uspGetEmployeeManagers(?)}");  
          4.  pstmt.setInt(150);  
          5.  ResultSet rs = pstmt.executeQuery();  
          6.  while (rs.next()) ...{  
          7.  System.out.println("EMPLOYEE:");  
          8.  System.out.println(rs.getString("LastName") + ", " + rs.getString("FirstName"));  
          9.  System.out.println("MANAGER:");  
          10.  System.out.println(rs.getString("ManagerLastName") + ", " + rs.getString("ManagerFirstName"));  
          11.  System.out.println();  
          12.  }  
          13.  rs.close();  
          14.  pstmt.close();  
          15.  }  
          16.  catch (Exception e) ...{  
          17.  e.printStackTrace();  
          18.  }  
          19. }

            3、使用帶有輸出參數(shù)的存儲過程

            使用 JDBC 驅(qū)動程序調(diào)用此類存儲過程時,必須結(jié)合 SQLServerConnection 類的 prepareCall 方法使用 call SQL 轉(zhuǎn)義序列。帶有 OUT 參數(shù)的 call 轉(zhuǎn)義序列的語法如下所示:

          {call procedure-name[([parameter][,[parameter]]...)]}

            構(gòu)造 call 轉(zhuǎn)義序列時,請使用 ?(問號)字符來指定 OUT 參數(shù)。此字符充當(dāng)要從該存儲過程返回的參數(shù)值的占位符。要為 OUT 參數(shù)指定值,必須在運行存儲過程前使用 SQLServerCallableStatement 類的 registerOutParameter 方法指定各參數(shù)的數(shù)據(jù)類型。

            使用 registerOutParameter 方法為 OUT 參數(shù)指定的值必須是 java.sql.Types 所包含的 JDBC 數(shù)據(jù)類型之一,而它又被映射成本地 SQL Server 數(shù)據(jù)類型之一。有關(guān) JDBC 和 SQL Server 數(shù)據(jù)類型的詳細(xì)信息,請參閱了解 JDBC 驅(qū)動程序數(shù)據(jù)類型。

            當(dāng)您對于 OUT 參數(shù)向 registerOutParameter 方法傳遞一個值時,不僅必須指定要用于此參數(shù)的數(shù)據(jù)類型,而且必須在存儲過程中指定此參數(shù)的序號位置或此參數(shù)的名稱。例如,如果存儲過程包含單個 OUT 參數(shù),則其序數(shù)值為 1;如果存儲過程包含兩個參數(shù),則第一個序數(shù)值為 1,第二個序數(shù)值為 2。

           作為實例,在 SQL Server 2005 AdventureWorks 示例數(shù)據(jù)庫中創(chuàng)建以下存儲過程: 根據(jù)指定的整數(shù) IN 參數(shù) (employeeID),該存儲過程也返回單個整數(shù) OUT 參數(shù) (managerID)。根據(jù) HumanResources.Employee 表中包含的 EmployeeID,OUT 參數(shù)中返回的值為 ManagerID。

            在下面的實例中,將向此函數(shù)傳遞 AdventureWorks 示例數(shù)據(jù)庫的打開連接,然后使用 execute 方法調(diào)用 GetImmediateManager 存儲過程:

          1. public static void executeStoredProcedure(Connection con) ...{  
          2.  try ...{  
          3.  CallableStatement cstmt = con.prepareCall("{call dbo.GetImmediateManager(?, ?)}");  
          4.  cstmt.setInt(15);  
          5.  cstmt.registerOutParameter(2, java.sql.Types.INTEGER);  
          6.  cstmt.execute();  
          7.  System.out.println("MANAGER ID: " + cstmt.getInt(2));  
          8.  }  
          9.  catch (Exception e) ...{  
          10.  e.printStackTrace();  
          11.  }  
          12. }

            本示例使用序號位置來標(biāo)識參數(shù)。或者,也可以使用參數(shù)的名稱(而非其序號位置)來標(biāo)識此參數(shù)。下面的代碼示例修改了上一個示例,以說明如何在 Java 應(yīng)用程序中使用命名參數(shù)。請注意,這些參數(shù)名稱對應(yīng)于存儲過程的定義中的參數(shù)名稱: 11x16CREATE PROCEDURE GetImmediateManager

          1.  @employeeID INT,  
          2.  @managerID INT OUTPUT 
          3. AS 
          4. BEGIN 
          5.  SELECT @managerID = ManagerID  
          6.  FROM HumanResources.Employee  
          7.  WHERE EmployeeID = @employeeID  
          8. END

            存儲過程可能返回更新計數(shù)和多個結(jié)果集。Microsoft SQL Server 2005 JDBC Driver 遵循 JDBC 3.0 規(guī)范,此規(guī)范規(guī)定在檢索 OUT 參數(shù)之前應(yīng)檢索多個結(jié)果集和更新計數(shù)。也就是說,應(yīng)用程序應(yīng)先檢索所有 ResultSet 對象和更新計數(shù),然后使用 CallableStatement.getter 方法檢索 OUT 參數(shù)。否則,當(dāng)檢索 OUT 參數(shù)時,尚未檢索的 ResultSet 對象和更新計數(shù)將丟失。

            4、使用帶有返回狀態(tài)的存儲過程

            使用 JDBC 驅(qū)動程序調(diào)用這種存儲過程時,必須結(jié)合 SQLServerConnection 類的 prepareCall 方法使用 call SQL 轉(zhuǎn)義序列。返回狀態(tài)參數(shù)的 call 轉(zhuǎn)義序列的語法如下所示:

          {[?=]call procedure-name[([parameter][,[parameter]]...)]}

            構(gòu)造 call 轉(zhuǎn)義序列時,請使用 ?(問號)字符來指定返回狀態(tài)參數(shù)。此字符充當(dāng)要從該存儲過程返回的參數(shù)值的占位符。要為返回狀態(tài)參數(shù)指定值,必須在執(zhí)行存儲過程前使用 SQLServerCallableStatement 類的 registerOutParameter 方法指定參數(shù)的數(shù)據(jù)類型。

            此外,向 registerOutParameter 方法傳遞返回狀態(tài)參數(shù)值時,不僅需要指定要使用的參數(shù)的數(shù)據(jù)類型,還必須指定參數(shù)在存儲過程中的序數(shù)位置。對于返回狀態(tài)參數(shù),其序數(shù)位置始終為 1,這是因為它始終是調(diào)用存儲過程時的第一個參數(shù)。盡管 SQLServerCallableStatement 類支持使用參數(shù)的名稱來指示特定參數(shù),但您只能對返回狀態(tài)參數(shù)使用參數(shù)的序號位置編號。

            作為實例,在 SQL Server 2005 AdventureWorks 示例數(shù)據(jù)庫中創(chuàng)建以下存儲過程:

          1. CREATE PROCEDURE CheckContactCity  
          2.  (@cityName CHAR(50))  
          3. AS 
          4. BEGIN 
          5.  IF ((SELECT COUNT(*)  
          6.  FROM Person.Address  
          7.  WHERE City = @cityName) > 1)  
          8.  RETURN 1  
          9. ELSE 
          10.  RETURN 0  
          11. END

            該存儲過程返回狀態(tài)值 1 或 0,這取決于是否能在表 Person.Address 中找到 cityName 參數(shù)指定的城市。

           在下面的實例中,將向此函數(shù)傳遞 AdventureWorks 示例數(shù)據(jù)庫的打開連接,然后使用 execute 方法調(diào)用 CheckContactCity 存儲過程:

          1.  public static void executeStoredProcedure(Connection con) ...{  
          2.  try ...{  
          3.  CallableStatement cstmt = con.prepareCall("{? = call dbo.CheckContactCity(?)}");  
          4.  cstmt.registerOutParameter(1, java.sql.Types.INTEGER);  
          5.  cstmt.setString(2, "Atlanta");  
          6.  cstmt.execute();  
          7.  System.out.println("RETURN STATUS: " + cstmt.getInt(1));  
          8.  }  
          9.  cstmt.close();  
          10.  catch (Exception e) ...{  
          11.  e.printStackTrace();  
          12.  }  
          13. }

            5、使用帶有更新計數(shù)的存儲過程

            使用 SQLServerCallableStatement 類構(gòu)建對存儲過程的調(diào)用之后,可以使用 execute 或 executeUpdate 方法中的任意一個來調(diào)用此存儲過程。executeUpdate 方法將返回一個 int 值,該值包含受此存儲過程影響的行數(shù),但 execute 方法不返回此值。如果使用 execute 方法,并且希望獲得受影響的行數(shù)計數(shù),則可以在運行存儲過程后調(diào)用 getUpdateCount 方法。

            作為實例,在 SQL Server 2005 AdventureWorks 示例數(shù)據(jù)庫中創(chuàng)建以下表和存儲過程:

          1. CREATE TABLE TestTable  
          2.  (Col1 int IDENTITY,  
          3.  Col2 varchar(50),  
          4.  Col3 int);  
          5.  
          6. CREATE PROCEDURE UpdateTestTable  
          7.  @Col2 varchar(50),  
          8.  @Col3 int 
          9. AS 
          10. BEGIN 
          11.  UPDATE TestTable  
          12.  SET Col2 = @Col2, Col3 = @Col3  
          13. END;

            在下面的實例中,將向此函數(shù)傳遞 AdventureWorks 示例數(shù)據(jù)庫的打開連接,并使用 execute 方法調(diào)用 UpdateTestTable 存儲過程,然后使用 getUpdateCount 方法返回受存儲過程影響的行計數(shù)。

          1. public static void executeUpdateStoredProcedure(Connection con) ...{  
          2.  try ...{  
          3.  CallableStatement cstmt = con.prepareCall("{call dbo.UpdateTestTable(?, ?)}");  
          4.  cstmt.setString(1, "A");  
          5.  cstmt.setInt(2, 100);  
          6.  cstmt.execute();  
          7.  int count = cstmt.getUpdateCount();  
          8.  cstmt.close();  
          9.  
          10.  System.out.println("ROWS AFFECTED: " + count);  
          11.  }  
          12.  catch (Exception e) ...{  
          13.  e.printStackTrace();

          posted @ 2012-05-14 09:51 順其自然EVO 閱讀(150) | 評論 (0)編輯 收藏

          watir+ruby(第一講)安裝文件下載 (windows下 linux下請用watir——webdriver)

          第一步:JDK下載

          官方地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin-b32-windows-i586-p-12_sep_2008.exe

          其他地址;http://www.xin126.cn/soft_show.asp?id=17


          第二步:eclipse下載地址(圖1):

          http://www.eclipse.org/downloads/


          第三步:ruby插件下載地址(圖2):

          http://download.eclipse.org/technology/dltk/downloads/drops/R3.0/S-3.0.1-201108261011/

          圖中兩個都需要下載(下載SDK)


          第四步:ruby1.8.7下載.exe (圖3)

          http://rubyforge.org/frs/?group_id=167


          第五步:rubygems1.8.7下載.zip(圖4)

          http://rubyforge.org/frs/?group_id=126


          第六步: watir1.6.5 下載圖中三個文件(圖5)

          http://rubyforge.org/frs/?group_id=104&release_id=28016


          第七步:火狐瀏覽器下載

          http://www.hacker.cn/Get/gjrj/06102608545293311.shtml



          1.jpg (11.33 KB, 下載次數(shù): 4)

          1.jpg


          2.jpg (13.05 KB, 下載次數(shù): 7)

          2.jpg


          3.jpg (6.22 KB, 下載次數(shù): 2)

          3.jpg


          4.jpg (6.08 KB, 下載次數(shù): 7)

          4.jpg


          5.jpg (5.79 KB, 下載次數(shù): 3)

          5.jpg


          框架運行效果展示圖.jpg (35.99 KB, 下載次數(shù): 3)

          框架運行效果展示圖.jpg

          posted @ 2012-05-11 11:15 順其自然EVO 閱讀(1645) | 評論 (0)編輯 收藏

          部署linux(ubuntu11.04) 中ruby&watir運行環(huán)境

           Ubuntu Linux 11.04ruby&watir運行環(huán)境:

          Step 1.Ruby安裝

          $sudo apt-get install ruby

          查看是否安裝成功:

          $ ruby -v

          ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux]



          Step 2. RubyGems安裝(管理ruby包)

          $sudo apt-get install rubygems1.8

          查看是否安裝成功:

          $ gem -v

          1.3.7

          Step 3.更新gem update

          如果直接使用命令sudo gem update –system,則會報錯如下:

          $ gem update –system

          ERROR: While executing gem ... (RuntimeError)

          gem update --system is disabled on Debian, because it will

          overwrite the content of the rubygems Debian package......

          解決方法:
          $sudo gem install rubygems-update
          Successfully installed rubygems-update-1.3.7
          再執(zhí)行update_rubygems更新命令:
          $sudo /var/lib/gems/1.8/bin/update_rubygems
          RubyGems installed the following executables:/usr/bin/gem1.8

          Step4.watir-webdriver安裝(支持iefirefox,chromeand Opera)
          $sudo gem install watir-webdriver --no-ri --no-rdoc
          (...)
          Successfully installed watir-webdriver-0.2.8
          4 gems installed
          Let's check if it can drive Firefox :

          wdd@ubuntu:~$ irb
          irb(main):001:0> require 'rubygems'
          => true
          irb(main):002:0> require 'watir-webdriver'
          => true
          irb(main):003:0>browser = Watir::Browser.new :ff
          /usr/lib/ruby/gems/1.8/gems/selenium-webdriver- 2.13.0/lib/selenium/webdriver/common/platform.rb:129: warning: Insecure world writable dir /opt in PATH, mode 040777=> #<Watir::Browser:0x..fb6fb4f80 url="about:blank" title="">
          irb(main):004:0> browser.goto('www.google.com')
          => "http://www.google.com.hk/"

          Note:
          If you want to use chrome,you should install chrome first.You do this:
          browser = Watir::Browser.new :chrome
          if you use ie or Opera, do this:
          browser = Watir::Browser.new :ie
          browser = Watir::Browser.new :opera
          Start your script!

          posted @ 2012-05-11 11:13 順其自然EVO 閱讀(846) | 評論 (1)編輯 收藏

          軟件評測師的目標(biāo)和任務(wù)

            評測,顧名思義,是評價和測試。因此,軟件評測師是通過編寫測試方案并按照測試方案和流程對軟件產(chǎn)品進(jìn)行功能和性能測試,檢查產(chǎn)品是否有缺陷,性能是否穩(wěn)定,并給出相應(yīng)的評價的那些專業(yè)技術(shù)人員。作為軟件開發(fā)的重要環(huán)節(jié),軟件測試越來越受到人們的重視。隨著軟件開發(fā)規(guī)模的增大、復(fù)雜程度的增加,以尋找軟件中的錯誤為目的測試工作就顯得更加困難。為了盡可能多地找出程序中的錯誤,生產(chǎn)出高質(zhì)量的軟件產(chǎn)品,需要大量的軟件評測人員,因此軟件評測工程師就應(yīng)運而生了。

            對軟件進(jìn)行評價的基礎(chǔ)是測試,測試的過程就是找出與軟件功能和性能不一致的地方,并進(jìn)行分析。軟件評測師的主要工作就是軟件測試。

             軟件危機(jī)曾經(jīng)是軟件界甚至整個計算機(jī)界最熱門的話題。為了解決這場危機(jī),軟件從業(yè)人員、專家和學(xué)者做出了大量的努力。軟件是由人來完成的,在目前的技術(shù) 上不能避免錯誤,有錯是軟件的屬性,是很難改變的。現(xiàn)在人們已經(jīng)逐步認(rèn)識到所謂的軟件危機(jī)實際上僅是一種狀況,那就是軟件中有錯誤,正是這些錯誤導(dǎo)致了軟 件開發(fā)在成本、進(jìn)度和質(zhì)量上的失控。因此,必須面對現(xiàn)實,避免軟件中錯誤的產(chǎn)生和消除已經(jīng)產(chǎn)生的錯誤,使程序中的錯誤密度達(dá)到盡可能低的程度。

            實踐經(jīng)驗證明,軟件測試是軟件開發(fā)過程中的一個重要步驟,或者說測試應(yīng)該貫穿在軟件開發(fā)過程的每一個階段。軟件測試所起到的作用就是:能夠確保在軟件開發(fā)的過程中,隨時發(fā)現(xiàn)問題,方便開發(fā)人員及時修改。

            軟件測試的最終目的是提交用戶一個高可用性產(chǎn)品,為了盡可能多地找出錯誤,測試的重點應(yīng)該是軟件比較復(fù)雜的部分或是以前出錯比較多的位置。為了給最終用戶提供具有一定可信度的質(zhì)量評價,測試的重點就應(yīng)該直接針對在實際應(yīng)用中會經(jīng)常用到的業(yè)務(wù)規(guī)則。

            Grenford J. Myers在《The Art of Software Testing》一書對軟件測試有如下的觀點:

            ① 軟件測試是為了發(fā)現(xiàn)錯誤而執(zhí)行程序的過程;

            ② 測試是為了證明程序有錯,而不是證明程序無錯誤;

            ③ 一個好的測試用例是在于它能發(fā)現(xiàn)至今未發(fā)現(xiàn)的錯誤;

            ④ 一個成功的測試是發(fā)現(xiàn)了至今未發(fā)現(xiàn)的錯誤的測試。

            因此,測試并不僅僅是為了要找出錯誤。通過分析錯誤產(chǎn)生的原因和錯誤的分布特征,可以幫助項目管理者發(fā)現(xiàn)當(dāng)前所采用的軟件過程的缺陷,以便改進(jìn)。同時,這種分析也能幫助我們設(shè)計出有針對性的檢測方法,改善測試的有效性。另外,沒有發(fā)現(xiàn)錯誤的測試也是有價值的,完整的測試是評定測試質(zhì)量的一種方法。

            對于軟件測試人員來說,其目標(biāo)和任務(wù)就是:

            1、軟件測試員的基本目標(biāo)是發(fā)現(xiàn)軟件缺陷

            軟件測試員的基本目標(biāo)是發(fā)現(xiàn)軟件缺陷,這是做好測試的首要條件。

            2、軟件測試員追求的是盡可能早的找出軟件缺陷

             因為軟件的修復(fù)費用,隨著軟件生命周期的推移,將數(shù)十倍的增長,所以軟件測試員應(yīng)盡可能早的找出軟件缺陷。對大型的軟件,在軟件開發(fā)的同時,就應(yīng)該有緊 隨其后的測試,如果等到產(chǎn)品已經(jīng)開發(fā)完畢才開始測試,非常有可能引起大量耗時費力的返工。怎樣才能有效的用這些方法盡早的發(fā)現(xiàn)軟件缺陷,需要大家在工作實 踐中不斷的摸索、總結(jié),進(jìn)而不斷的提高自己的測試能力。

            3、軟件測試員必需確保找出的軟件缺陷得以關(guān)閉

             軟件測試人員必需確保找出的軟件缺陷得以關(guān)閉。關(guān)閉的含義不是要軟件缺陷在任何時候都必須得到修復(fù)。軟件測試員需要對自己找出的軟件缺陷保持一種平常 心,并不是辛苦找出的每個軟件缺陷都是必要修復(fù)的。可能是由于沒有足夠的時間、不算真正的軟件缺陷、修復(fù)的風(fēng)險太大等原因,產(chǎn)品開發(fā)小組可以決定對一些軟 件缺陷不作修復(fù)。

            雖然軟件測試員需要對自己找出的軟件缺陷保持一種平常心,但同時又必須堅持有始有終的原則,跟蹤每一個軟件缺陷的處理 結(jié)果,確保軟件缺陷得以關(guān)閉。關(guān)閉軟件缺陷的前提可以是缺陷得以修復(fù)或決定不作修復(fù)。而缺陷是否需要修復(fù)的最終決定權(quán)在軟件的最終負(fù)責(zé)人,檢查缺陷得以關(guān) 閉的責(zé)任在測試人員。但值得指出的是,雖然測試工程師找出了錯誤,但決定是否修改的權(quán)限并不是在測試工程師手上的,最終是由項目經(jīng)理來決定的。

            4、軟件測試員依據(jù)事實對軟件做出評價

            軟件測試人員對軟件的測試結(jié)束后,通過對測試結(jié)果進(jìn)行分析,然后實事求是地對軟件產(chǎn)品的功能和性能做出恰當(dāng)?shù)脑u價。

          posted @ 2012-05-11 09:58 順其自然EVO 閱讀(198) | 評論 (0)編輯 收藏

          基于AMF協(xié)議的Flex應(yīng)用程序的性能測試

           接觸過Flex應(yīng)用的,基本上對于其表現(xiàn)層的視覺效果都是非常贊賞的,也正是由于其華麗的外表掩蓋了其諸多內(nèi)在的缺陷,比如說響應(yīng)速度、內(nèi)存泄漏等等性能問題,對于大部分的Flex開發(fā)程序員或者是測試人員都是非常頭痛的事情。本人最近就碰到基于Flex應(yīng)用程序的性能測試, 由于它本身的特殊性,通信組建、協(xié)議基本上都是Adobe自己開發(fā)的,所以基本上通用的測試工具對他支持都是不太理想的。通過一系列的摸索,最終還是得把 注意力轉(zhuǎn)移到Flex本身上來,全面去解析AMF協(xié)議,其實AMF協(xié)議還是走HTTP協(xié)議的,但從執(zhí)行效率上來說,我們不能單純通過HTTP協(xié)議來模擬其 執(zhí)行過程,因為中間必須要走AMF協(xié)議,雖然LoadRunner也 有支持AMF協(xié)議,但AMF本身是需要Flash Player來支持,錄制得到的腳本,不易于理解和分析,我們無法很好分析其執(zhí)行過程,而且它封包和解包都是二進(jìn)制格式,如果以這種方案去執(zhí)行,我們就需 要解析它每一次封包和解包過程,相當(dāng)于要去深入到AMF協(xié)議包解析過程,這樣就把簡單的問題復(fù)雜化。本身對于C/S應(yīng)用程序的性能測試,最大的問題就是數(shù) 據(jù)包解析,通過LoadRunner去壓測,就可能要面臨丟包的情況。所以通常情況下,我們?yōu)榱吮WC協(xié)議數(shù)據(jù)包傳輸?shù)耐暾裕M量去避開直接去與協(xié)議數(shù)據(jù) 包打交道,而且是通過上層的封裝方式進(jìn)行請求,而不去干預(yù)內(nèi)在的復(fù)雜過程,這樣就既能保證數(shù)據(jù)傳輸?shù)耐暾裕瑫r也保證與業(yè)務(wù)邏輯實現(xiàn)方式的一致性,達(dá)到 真實環(huán)境的壓測方案。

            下面我們將具體了解哈AMF協(xié)議,并通過模擬Client與Server實現(xiàn)AMF協(xié)議通信的連接方式來完成大并發(fā)的壓力測試。

            AMF是Adobe獨家開發(fā)出來的通信協(xié)議,它采用二進(jìn)制壓縮,序列化、反序列化、傳輸數(shù)據(jù),從而為Flash 播放器與Flash Remoting網(wǎng)關(guān)通信提供了一種輕量級的、高效能的通信方式。

             模擬AMF請求與Server端建立通信,Adobe官方提供了一個Server端的通信服務(wù)就是BlazeDS,F(xiàn)lex將數(shù)據(jù)通過AMF協(xié)議轉(zhuǎn)換成 二進(jìn)制格式進(jìn)行傳輸給Server端的BlazeDS服務(wù),然后BlazeDS再將數(shù)據(jù)解析成Java需要的格式,完成Flex客戶端與Server端的 通信過程。因此通過進(jìn)一步分析發(fā)現(xiàn),我們的目的就是要模擬AMF與BlazeDS建立連接,就解決了問題了。這里,就是利用Java來模擬AMF請求,通 過AMFConnection連接Blazeds接口,具體Demo代碼如下:

          package org.test.service.TestLogin;

          import flex.messaging.io.amf.client.AMFConnection;
          import flex.messaging.io.amf.client.exceptions.ClientStatusException;
          import flex.messaging.io.amf.client.exceptions.ServerStatusException;

          public class AMFDemo {

              public static void main(String[] args) {
                  // 創(chuàng)建AMF連接
                  AMFConnection amfCon = new AMFConnection();
                 
                  //連接 remote URL
                  String url = http://localhost:8080/TestLogin/messagebroker/amf ;
                   try{
                      amfCon.connect(url);
                  }catch(ClientStatusException cse){
                      System.out.println(cse);
                      return ;
                  }
                 
                  TestLogin result ;   
                  try{
                      result = (TestLogin)amfCon.call("TestLogin.login","username","passwd");//傳輸對象的參數(shù),登錄用戶、密碼
                  }catch(ClientStatusException ce){
                      System.out.println(ce);
                  }catch(ServerStatusException se){
                      System.out.println(se);
                  }
                  amfCon.close();       
                  System.out.println("Sucessfull!!!");
              }
          }

           如果以上連接測試成功之后,那么接下來的問題就好解決了,那就是模擬并發(fā),對于Java來說,那就是多線程的事兒了,通過多線程來控制實現(xiàn)并發(fā)用戶量,完成BlaseDS接口的壓力測試。多線程代碼實現(xiàn)如下:

          package org.test.service.TestLogin;

          import flex.messaging.io.amf.client.AMFConnection;
          import flex.messaging.io.amf.client.exceptions.ClientStatusException;
          import flex.messaging.io.amf.client.exceptions.ServerStatusException;

          public class AMFDemo implements Runnable{

                  public void run(){
                  // 創(chuàng)建AMF連接
                  AMFConnection amfCon = new AMFConnection();
                 
                  //連接 remote URL
                  String url = http://localhost:8080/TestLogin/messagebroker/amf ;
                  try{
                      amfCon.connect(url);
                  }catch(ClientStatusException cse){
                      System.out.println(cse);
                      return ;
                  }
                  //循環(huán)100次
                  for(int i=0; i<100; i++){
                      TestLogin result ;   
                      try{
                          Thread.sleep(1000L);
                          long TestStart = System.currentTimeMillis();
                          result = (TestLogin)amfCon.call("TestLogin.login","username","passwd");//傳輸對象的參數(shù),登錄用戶、密碼
                          System.out.println("login:" + (System.currentTimeMillis() - TestStart));//打印出登錄的響應(yīng)時間
                      }catch(ClientStatusException ce){
                          System.out.println(ce);
                      }catch(ServerStatusException se){
                          System.out.println(se);
                      }catch (final InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
                  amfCon.close();       
                  System.out.println("Sucessfull!!!");
              }
          }   
             
          public class AMFDemoTest {
              //創(chuàng)建100個線程
              public static void main(String[] args) throws Exception {
                  for (int i = 0; i < 100; i++) {
                      Runnable runnable = new AMFDemo();
                      new Thread(runnable).start();
                  }
              }

          }

            通過Java模擬AMF請求與BlazeDS建立通信連接,完成基于AMF協(xié)議的Flex應(yīng)用程序的壓力測試,拋棄傳統(tǒng)的工具壓測方式,從而尋 找最適合FLex本身的性能測試方案。當(dāng)然,這個只是一種純代碼方式來實現(xiàn),我們也可以借助通用工具來完成,至少在完成以上的代碼實現(xiàn)過程,之后可以通過 LoadRunner或者是JMeter來調(diào)用Java代碼完成,不過似乎JMeter對于Java支持更方便。使用工具的目的其實為了采樣壓力測試的數(shù) 據(jù)方便分析,而真正實現(xiàn)壓力測試,其實不管是工具還是腳本,其實都是通過模擬底層的交互方式來達(dá)到同樣的目的。

            作為一名測試人員,對于Java與Flex的通信方式的理解遠(yuǎn)不如開發(fā)人員,所以可能以上對于BlazeDS的通信機(jī)制描述難免有誤。但這里并 不只是記錄如何實現(xiàn)一種壓力測試,而是表達(dá)一種個人對于性能測試思想的理解,很多時候不要一味地去追求自動化工具的強(qiáng)大,而忽略了其性能測試本身的思想。 希望能通過不斷總結(jié),來逐步提高自己!

          posted @ 2012-05-11 09:57 順其自然EVO 閱讀(390) | 評論 (0)編輯 收藏

          如何診斷Oracle Redo Log引發(fā)的性能問題

           一、Rodo Log性能調(diào)整目標(biāo):

            在能夠影響Oracle性 能的諸多因素中,Redo Log相關(guān)的因素從某種程度上可以說是最為重要同時也是最值得關(guān)注的。因為在一個OLTP系統(tǒng)中Oracle通過各種技術(shù)以及優(yōu)良的設(shè)計,盡量做到將大部 分操作在內(nèi)存中完成,以便最大程度的提升性能。因此在Oracle的諸多后臺進(jìn)程以及用戶進(jìn)程的大部分操作都是內(nèi)存操作,而且這些操作會通過延遲寫入技術(shù) 盡可能的將磁盤I/O操作滯后。但是在這些操作中卻有某些例外,其中最明顯的就是針對Redo Log的操作。

            在Oracle中針對Redo Log的操作主要由LGWR進(jìn)程完成,這個進(jìn)程可以說是Oracle所有后臺進(jìn)程中最繁忙的進(jìn)程,而且這個進(jìn)程可能要頻繁的進(jìn)行I/O操作,這是因為Oracle出于數(shù)據(jù)安全的考慮必須保證聯(lián)機(jī)在線重做日志可 靠的寫入日志文件,以便在發(fā)生崩潰時能夠有效恢復(fù)數(shù)據(jù),而真正的數(shù)據(jù)可能會等一些時間延遲寫入數(shù)據(jù)文件。這種特點在Oracle的各個后臺進(jìn)程中顯得有些 獨樹一幟。另外LGWR全局唯一,即一個實例只能有一個活動的LGWR進(jìn)程,由于要進(jìn)行頻繁的I/O操作可想而知是很容易造成LGWR進(jìn)程競爭的。由于 LGWR在Oracle實例結(jié)構(gòu)設(shè)計中的特殊地位,一旦出現(xiàn)LGWR性能瓶頸,那么對整個系統(tǒng)的性能影響將會是極為嚴(yán)重的,同時對數(shù)據(jù)安全也是一個潛在的 威脅。

            因此作為Oracle日常的數(shù)據(jù)庫管 理,我們要給與這部分相當(dāng)?shù)年P(guān)注,盡早發(fā)現(xiàn)問題,盡早作出調(diào)整。調(diào)整的目標(biāo)就是要做到Log_Buffer大小適中(不要過大,也不能太小),要滿足用戶 進(jìn)程的使用需要,每當(dāng)系統(tǒng)負(fù)載有一個明顯的增加時,就應(yīng)該考慮調(diào)整它的大小。比如因為業(yè)務(wù)拓展當(dāng)前系統(tǒng)固定用戶數(shù)量從1萬人猛增到3萬人,那么就應(yīng)該對 Log_Buffer大小給與關(guān)注。另外就是要做到日志文件的大小適中,日志組的日志文件數(shù)量合適,不能影響LGWR寫日志文件的性能,不能造成日志文件 間的寫入競爭,不能在日志切換歸檔發(fā)生時引發(fā)磁盤競爭等等。

            二、監(jiān)控與問題排查:

            在進(jìn)行Redo Log問題監(jiān)控時,主要關(guān)注兩個方面:日志緩沖區(qū)空間使用的等待情況和日志緩沖區(qū)數(shù)據(jù)槽的分配情況。通過這兩方面的監(jiān)控并配合一些問題排查手段,通常可以發(fā)現(xiàn)大量問題。

            (1)日志緩沖區(qū)空間使用的等待情況:

            可以通過查詢v$session_wait來監(jiān)控日志緩沖區(qū)空間使用的等待情況,通過如下SQL語句進(jìn)行查詢:

          select sid,event,seconds_in_wait,state
          from v$session_wait
          where event='log buffer space%';

            以上的查詢中可以通過觀察seconds_in_wait的數(shù)值來分析問題,這個數(shù)值可以顯示如下問題:日志切換緩慢引發(fā)的等待、LGWR寫入緩慢引發(fā)的等待、日志文件寫入引起的磁盤競爭引發(fā)的等待。

            這些等待的發(fā)生可能是由于如下問題引起的:

            1、日志文件寫入時存在磁盤競爭:

            這種情況多見于日志切換發(fā)生時,由于日志文件組的規(guī)劃不當(dāng),或者存放日志文件的磁盤寫入速度緩慢,或者是因為磁盤RADI類型不當(dāng)都會引發(fā)這個問題,如果懷疑村在這些情況,可以通過如下語句進(jìn)行監(jiān)控:

          select event,total_waits,time_waited,average_wait
          from v$system_event
          where event like 'log file switch completion%';

            可以通過觀察total_waits,time_waited,average_wait數(shù)值來分析問題,如果這些值過高(注意何謂“過高”,不同系統(tǒng)考量標(biāo)準(zhǔn)不一樣,要具體分析),那么說明存在以上問題。此時可以通過如下措施解決:

            ● 將同一日志文件組的各個成員分配到不同的磁盤上,進(jìn)而減少日志寫入以及日志切換和日志歸檔時引發(fā)的競爭;

            ● 將日志文件盡可能存放在快速的磁盤上;

            ● 要合理選擇RADI類型對磁盤進(jìn)行條帶化,通常不要選擇RADI5來作為日志文件磁盤的RADI類型,通常推薦使用RADI10;

            ● 可以增加REDO LOG文件大小,來延緩日志切換,下面是一個增加日志文件大小的方法;

            假如原來有3個小的redo log file,下面是UNIX環(huán)境下的一個例子:

            第一步:往數(shù)據(jù)庫添加三個大的redo logfile

          SVRMGRL>ALTER DATABASE ADD LOGFILE GROUP 4
          ('/opt/oradata/app/redo04.log',
          '/ora_bak/oradata2/redolog/redo04.log') size 16M reuse;

          SVRMGRL>ALTER DATABASE ADD LOGFILE GROUP 5
          ('/opt/oradata/app/redo05.log',
          '/ora_bak/oradata2/redolog/redo05.log') size 16M reuse;

          SVRMGRL>ALTER DATABASE ADD LOGFILE GROUP 6
          ('/opt/oradata/app/redo06.log',
          '/ora_bak/oradata2/redolog/redo06.log') size 16M reuse;

            第二步: 手工地做log switch,使新建的redo logfile起作用

          SVRMGRL>alter system switch logfile;

            此操作可以執(zhí)行一到幾次,使舊的redo logfile成invalid狀態(tài)。

            第三步:刪除原來舊的redo logfile

          SVRMGRL>alter database drop logfile group 1;
          SVRMGRL>alter database drop logfile group 2;
          SVRMGRL>alter database drop logfile group 3;

            2、檢查點發(fā)生時DBWR進(jìn)程沒有完成數(shù)據(jù)寫入引發(fā)等待:

            當(dāng)日志文件完成一個循環(huán)周期后再一次來到原來某個日志文件準(zhǔn)備進(jìn)行重新使用時,發(fā)現(xiàn)該日文件對應(yīng)的數(shù)據(jù)還沒有寫入相應(yīng)的數(shù)據(jù)文件中,此時LGWR必須等待DBWR完成寫入,從而引發(fā)等待。

            如果懷疑存在這個問題可以通過如下查詢來進(jìn)行監(jiān)控:

          select event,total_waits,time_waited,average_wait
          from v$system_event
          where event like 'log file switch (check%';

            通過total_waits,time_waited,average_wait這些數(shù)值的大小來判斷分析問題,如果還不能確定,那么可以查看 一下Oracle的alert.log文件看一下相關(guān)時間內(nèi)是否存在“checkpoint not complete”。如果存在那么證明日志文件的操作性能被DBWR進(jìn)程所拖累。此時可以通過如下措施解決:

            ● 檢查存放數(shù)據(jù)文件的磁盤是否存在I/O瓶頸(如:是否存在讀寫競爭、是否存在物理損壞、是否存在RADI類型不符等);

            ● 合理規(guī)劃調(diào)整日志文件組日志文件的數(shù)量和大小;

            ● 合理設(shè)置FAST_START_MTTR_TARGET參數(shù),以便設(shè)置一個合適的數(shù)值來控制檢查點的發(fā)生;

            ● 可以考慮增加DBWR進(jìn)程的數(shù)量,Oracle最多可以有10個DBWR進(jìn)程;

            ● 如果條件允許,可以開啟異步I/O;

            3、由于日志歸檔引發(fā)的等待:

            當(dāng)歸檔發(fā)生時,歸檔日志進(jìn)程不能快速的進(jìn)行日志歸檔,從而導(dǎo)致了LGWR的等待。如果懷由此問題可以通過如下語句來監(jiān)控:

          select event,total_waits,time_waited,average_wait
          from v$system_event
          where event like 'log file switch (arch%';

            同樣通過total_waits,time_waited,average_wait這些數(shù)值來進(jìn)行問題分析,如果出現(xiàn)由于歸檔日志寫入緩慢引發(fā)的性能問題,可以采用如下辦法:

            ● 確定存放歸檔日志的磁盤空間沒有被寫滿,如果出現(xiàn)這種情況,那么要對歸檔日志進(jìn)行有限度的刪除,或者將這些歸檔日志移走如存放到磁帶庫上,或者分配更大的存儲空間;

            ● 增加日志文件組,從而為歸檔多留出一些時間;

            ● 增加多個歸檔進(jìn)程,Oracle最多允許10個歸檔進(jìn)程存在,在歸檔發(fā)生時如果LGWR進(jìn)程發(fā)現(xiàn)歸檔進(jìn)程ARCH出現(xiàn)不足時,會自動產(chǎn)生新的歸檔進(jìn)程,因 此如果系統(tǒng)負(fù)載有明顯增加預(yù)先分配足夠的歸檔進(jìn)程可以提高性能,可以使用alter system命令通過更改LOG_ARCHIVE_MAX_PROCESSES參數(shù)來改變歸檔進(jìn)程數(shù)目;

            (2)日志緩沖區(qū)數(shù)據(jù)槽的分配情況引發(fā)的等待:

            可以通過如下的語句來監(jiān)控日志緩沖區(qū)數(shù)據(jù)槽的分配情況的百分比:

          select r.value "retries",e.value "entries",r.value/e.value*100 "percentage"
          from v$sysstat t,v$sysstat e
          where r.name='redo buffer allocation retries'
          and e.name='redo entries';

            這個百分比值不能高于1%,如果這個數(shù)值頻繁增長,那么一定出現(xiàn)了Log_Buffer內(nèi)存空間不足,從而使得新產(chǎn)生的redo log entries不能寫入Log_Buffer中從而造成等待,這個等待是由于LGWR性能不佳寫日志文件過慢造成的,通常來說LGWR寫入速度都是非常快 速的可以保證新產(chǎn)生的redo log entries內(nèi)存空間使用的需要,即使在高負(fù)載情況下也不會出現(xiàn)太大問題,因而上面的問題通常發(fā)生機(jī)率較小,但是如果一旦發(fā)生,那么很有可能是由于日志 文件磁盤I/O規(guī)劃出現(xiàn)問題,或者日志文件磁盤出現(xiàn)物理損壞,因此在出現(xiàn)這種情況引發(fā)的性能問題時,主要應(yīng)該進(jìn)行日志文件磁盤I/O規(guī)劃以及日志文件磁盤 是否出現(xiàn)物理損傷方面的排查,同時也可能綜合應(yīng)用如Oracle的alert.log等相關(guān)文件進(jìn)行綜合分析。

          posted @ 2012-05-11 09:49 順其自然EVO 閱讀(1311) | 評論 (0)編輯 收藏

          淺析Java web程序之客戶端和服務(wù)器端交互原理

          1、協(xié)議

            a. TCP/IP整體構(gòu)架概述

            TCP/IP協(xié)議并不完全符合 OSI的七層參考模型。傳統(tǒng)的開放式系統(tǒng)互連參考模型,是一種通信協(xié)議的7層抽象的參考模型,其中每一層執(zhí)行某一特定任務(wù)。該模型的目的是使各種硬件在相 同的層次上相互通信。這7層是:物理層、數(shù)據(jù)鏈路層、網(wǎng)路層、傳輸層、話路層、表示層和應(yīng)用層。而TCP/IP通訊協(xié)議采用了4層的層級結(jié)構(gòu),每一層都呼 叫它的下一層所提供的網(wǎng)絡(luò)來完成自己的需求。這4層分別為:

            i. 應(yīng)用層:應(yīng)用程序間溝通的層,如超文本傳送協(xié)議(HTTP)、簡單電子郵件傳輸(SMTP)、文件傳輸協(xié)議(FTP)、網(wǎng)絡(luò)遠(yuǎn)程訪問協(xié)議(Telnet)等。

            ii. 傳輸層:在此層中,它提供了節(jié)點間的數(shù)據(jù)傳送服務(wù),如傳輸控制協(xié)議(TCP)、用戶數(shù)據(jù)報協(xié)議(UDP)等,TCP和UDP給數(shù)據(jù)包加入傳輸數(shù)據(jù)并把它傳輸?shù)较乱粚又校@一層負(fù)責(zé)傳送數(shù)據(jù),并且確定數(shù)據(jù)已被送達(dá)并接收。

            iii. 互連網(wǎng)絡(luò)層:負(fù)責(zé)提供基本的數(shù)據(jù)封包傳送功能,讓每一塊數(shù)據(jù)包都能夠到達(dá)目的主機(jī)(但不檢查是否被正確接收),如網(wǎng)際協(xié)議(IP)。

            iv. 網(wǎng)絡(luò)接口層:對實際的網(wǎng)絡(luò)媒體的管理,定義如何使用實際網(wǎng)絡(luò)(如Ethernet、Serial Line等)來傳送數(shù)據(jù)。

            b. HTTP協(xié)議介紹:

            i. HTTP是一種超文本傳送協(xié)議(HyperText Transfer Protocol),是一套計算機(jī)在網(wǎng)絡(luò)中通信的一種規(guī)則。在TCP/IP體系結(jié)構(gòu)中,HTTP屬于應(yīng)用層協(xié)議,位于TCP/IP協(xié)議的頂層

            ii. HTTP是一種無狀態(tài)的的協(xié)議,意思是指 在Web 瀏覽器(客戶端)和 Web 服務(wù)器之間不需要建立持久的連接。整個過程就是當(dāng)一個客戶端向服務(wù)器端發(fā)送一個請求(request),然后Web服務(wù)器返回一個響應(yīng) (response),之后連接就關(guān)閉了,在服務(wù)端此時是沒有保留連接的信息。

            iii. HTTP 遵循 請求/響應(yīng)(request/response) 模型的,所有的通信交互都被構(gòu)造在一套請求和響應(yīng)模型中。

            iv. 瀏覽WEB時,瀏覽器通過HTTP協(xié)議與WEB服務(wù)器交換信息,Web服務(wù)器向Web瀏覽器返回的文件都有與之相關(guān)的類型,這些信息類型的格式由MIME定義。

            c. 協(xié)議的java實現(xiàn)方式

            不論是TCP/IP協(xié)議也好,還是HTTP協(xié)議也好,java都是通過套接字(java.net.Socket)來實現(xiàn)的,可以參考我的另一篇技術(shù)博客:一個項目看java TCP/IP Socket編程(1.3版)

            2、HTTP報文接口及客戶端和服務(wù)器端交互原理

            a. HTTP定義的事務(wù)處理由以下四步組成:

            i. 建立連接:

             例如我在瀏覽器里輸入 http://cuishen.iteye.com,客戶端請求這個地址時即打開了web服務(wù)器HTTP端口的一個套接字。因為在網(wǎng)絡(luò)中間作為傳遞數(shù)據(jù)的 實體介質(zhì)就是網(wǎng)線,數(shù)據(jù)實質(zhì)上是通過IO流進(jìn)行輸出和輸入,這就不難理解我們?yōu)槭裁丛趯懸粋€Servlet的時候要引用 import java.io.*; 的原因 ,包括我們在向客戶端回發(fā)結(jié)果的時候要用到PrintWriter對象的println()方法。其實請求的這個地址還要加上端口號80,80可以不寫, 是因為瀏覽器默認(rèn)的端口號是80。

            在Java底層代碼中是這樣實現(xiàn)的,只不過它們已經(jīng)幫我們做了。

          1. Socket socket = new Socket("cuishen.iteye.com",80);    
          2. InputStream in = socket.getInputStream();    
          3. OutputStream out = socket.getOutputStream();

            ii. 客戶端發(fā)送HTTP請求報文(request)

            一旦建立了TCP連接,Web瀏覽器就會向Web服務(wù)器發(fā)送請求命令,是一個ASCII文本請求行,后跟0個或多個HTTP頭標(biāo),一個空行和實現(xiàn)請求的任意數(shù)據(jù)。

          即報文分四個部分:請求行,請求頭標(biāo),空行和請求數(shù)據(jù)

            1)請求行

            請求行由三個標(biāo)記組成:請求方法、請求URL和HTTP版本,中間用空格分開

            例如: GET cuishen.iteye.com/blog/242842 HTTP/1.1

            HTTP規(guī)范定義了8種可能的請求方法:(最常見的就是 GET 和 POST 兩種方法)

            ● GET -- 檢索URI中標(biāo)識資源的一個簡單請求
            ● HEAD -- 與GET方法相同,服務(wù)器只返回狀態(tài)行和頭標(biāo),并不返回請求文檔
            ● POST -- 服務(wù)器接受被寫入客戶端輸出流中的數(shù)據(jù)的請求
            ● PUT -- 服務(wù)器保存請求數(shù)據(jù)作為指定URI新內(nèi)容的請求
            ● DELETE -- 服務(wù)器刪除URI中命名的資源的請求
            ● OPTIONS -- 關(guān)于服務(wù)器支持的請求方法信息的請求
            ● TRACE -- Web服務(wù)器反饋Http請求和其頭標(biāo)的請求
            ● CONNECT -- 已文檔化但當(dāng)前未實現(xiàn)的一個方法,預(yù)留做隧道處理

            2)請求頭標(biāo)

            請求頭標(biāo):由key :value 健值組成,每行一對。請求頭標(biāo)用來通知服務(wù)器有關(guān)客戶端的功能和標(biāo)識。

            HOST -- 請求的哪一個服務(wù)器端地址,主地址,比如:我的技術(shù)blog:cuishen.iteye.com

            User-Agent -- 用戶即客戶端可以使用的瀏覽器 ,如: Mozilla/4.0

            Accept -- 即客戶端可以接受的MIME 類型列表,如image/gif、text/html、application/msword

            Content-Length -- 只適用于POST請求,以字節(jié)給出POST數(shù)據(jù)的尺寸

            3)空行

            發(fā)送回車符和退行,通知服務(wù)器以下不再有頭標(biāo)。

            4)請求數(shù)據(jù)

            使用POST傳送數(shù)據(jù),最常使用的是Content-Type和Content-Length頭標(biāo)。

            請求報文總結(jié):

            我們可以這樣寫出一個標(biāo)準(zhǔn)的 HTTP請求:

          POST /blog/242842 HTTP1.1
          HOST: cuishen.iteye.com/
          User-Agent: Mozilla/4.0
          Accpt: image/gif,text/html,application/pdf,image/png...
          key=value&key=value&key=value...... (POST()請求的數(shù)據(jù))

            這上面的一個例子意思是:

          我要去訪問的服務(wù)器端的地址是cuishen.iteye.com/ 它下面的資源 /blog/242842
          連起來就是: cuishen.iteye.com/blog/242842
          這個頁面用的是 HTTP1.1 規(guī)范,我的瀏覽器版本是Mozilla/4.0
          可以支持的MIME格式為 image/gif,text/html,application/pdf,image/png...等等

          這個MIME格式我們在servlet中寫法是:response.setContentType("text/html;charset=gb2312");
          或者在jsp中寫法是:<%@ page contentType="text/html;charset=gb2312"%>
          或者在html中寫法是:<meta http-equiv="content-Type" content="text/html; charset=gb2312">

            (c).空行:最后一個響應(yīng)頭標(biāo)之后是一個空行,發(fā)送回車符和退行,表明服務(wù)器以下不再有頭標(biāo)。

            (d).響應(yīng)數(shù)據(jù):HTML文檔和圖像等,也就是HTML本身。out.println("<html>......");寫到客戶端。

          1. <html>    
          2. <head>    
          3. <title>Welcome to cuishen's IT blog</title>    
          4. </head>    
          5. <body>    
          6. <!-- 這里是具體的內(nèi)容,看到了這里    
          7. 相信大家對 HTTP 工作原理及客戶端與服務(wù)器交互過程已經(jīng)很清楚了吧    
          8. -->     
          9. </body>    
          10. </html>

            iv. 服務(wù)器端關(guān)閉連接,客戶端解析回發(fā)響應(yīng)報文,恢復(fù)頁面

            1)瀏覽器先解析狀態(tài)行,查看請求是否成功的狀態(tài)代碼--HTTP響應(yīng)碼:404 400 200 ....

            2)解析每一個響應(yīng)頭標(biāo),如:

          ContentType: text/html;charset=gb2312
          Content-Length: 122 --- 響應(yīng)中的字節(jié)數(shù),只在瀏覽器使用永久(Keep-alive)HTTP連接時需要。

            3)讀取響應(yīng)數(shù)據(jù)HTML,根據(jù)標(biāo)簽<html></html>中的內(nèi)容恢復(fù)標(biāo)準(zhǔn)的HTML格式頁面或者其它。

            4)一個HTML 文檔可能包含其它的需要被載入的資源,瀏覽器會識別,并對這些資源再進(jìn)行額外的請求,這個過程可以是循環(huán)的方式一直到所有的數(shù)據(jù)都按照響應(yīng)頭標(biāo)中規(guī)定的格式恢復(fù)到頁面中。

            5)數(shù)據(jù)傳送完畢,服務(wù)器端關(guān)閉連接,即無狀態(tài)協(xié)議。

            3、總結(jié)

            不要被高深的名詞和理論嚇到,其實HTTP客戶端和服務(wù)器端的交互原理很簡單:即先是瀏覽器和服務(wù)器端建立Socket無狀態(tài)連接,也就是短連 接,然后通過IO流進(jìn)行報文信息(這個報文是嚴(yán)格遵循HTTP報文接口的)的交互,最后會話結(jié)束后就關(guān)閉連接。對于這些底層的協(xié)議和報文的打包解包交互的 實現(xiàn),其實java和瀏覽器早都已經(jīng)封裝好了,程序員只要專注于業(yè)務(wù)邏輯的實現(xiàn)就行啦,這些都不必關(guān)心!!


          posted @ 2012-05-11 09:48 順其自然EVO 閱讀(432) | 評論 (0)編輯 收藏

          快速找出數(shù)據(jù)庫的性能問題之:缺失索引 &無用的索引


          沒有用的索引

            正如在上一小節(jié)所的講的,創(chuàng)建一個索引是一個非常需要重視的問題,需要考慮很多的方面,因為,如果我們建立的索引沒有發(fā)揮作用,甚至說,查詢優(yōu)化器不采用我們的索引,那么就會帶來適得其反的效果。

            索引的維護(hù)是需要成本,甚至使得數(shù)據(jù)庫的性能變得很低,特別實在數(shù)據(jù)更新的時候。當(dāng)在數(shù)據(jù)表上面進(jìn)行數(shù)據(jù)的更新,刪除,和插入的時候,都會導(dǎo)致索引頁發(fā)生重新的調(diào)整,導(dǎo)致索引頁中的數(shù)據(jù)重新的排序,從而導(dǎo)致數(shù)據(jù)表被鎖定。

            所以,我們很有必要找出沒有發(fā)揮作用的索引,我們還是可以采用DMV來快速的查看:

            這里不否認(rèn),要完全明白上面的查詢的意思卻不是一件容易的事情,大家可以暫時不用懂,可以把這些腳本保存起來,作為一個小的工具使用。

            查詢結(jié)果如下:

            因為我這里采用的是一個示例數(shù)據(jù)庫,所以看到的結(jié)果不是很多,但是可以發(fā)現(xiàn):這些索引一些在被不斷的更新(user_updates),但是沒有被用過(system usage)。

            對無用索引的解決很簡單:刪除索引就OK了。

            關(guān)于腳本,請大家在附件中下載,可以保留起來,并且大家還可以修改,查詢指定的數(shù)據(jù)庫的情況。

            附件:scripts.zip  我們通過減少查詢中的不必要的讀取操作從而使得查詢的性能得到提升。一個查詢在數(shù)據(jù)庫中執(zhí)行的讀操作越多,那么就對磁盤,CPU,內(nèi)存的壓力越大。除非整個數(shù)據(jù)庫的數(shù)據(jù)全在在內(nèi)存中,否則每次的讀操作都會把數(shù)據(jù)從磁盤讀入到內(nèi)存中,然后返回。

            一個查詢在讀取一個資源的時候,通過加鎖會阻止其他的查詢對這個資源進(jìn)行修改,此時其他要操作這個資源的查詢就需要等待,從而導(dǎo)致了延時。

            誠然,有些等待是必須的,讀取操作也是必須的,但是一些因為我們代碼或者設(shè)計導(dǎo)致的過度的讀取操作和等待,那就會嚴(yán)重影響性能,尤其是當(dāng)數(shù)據(jù)庫的訪問量開始變大的時候。

            可以說在SQL Server中,最高效的讀取數(shù)據(jù)方式就是通過索引去獲取數(shù)據(jù)。如果在數(shù)據(jù)表中存在缺失索引的問題,結(jié)果可想而知。

            在本篇中,我們將會討論下面幾個議題:

            ● 如何識別缺失索引性能問題

            ● 識別沒有用的索引

            ● 如何解決上面的問題

            確實本篇講述的內(nèi)容涉及到了一些與數(shù)據(jù)庫性能調(diào)優(yōu)的話題,對于調(diào)優(yōu)而言,難點很多時候在于如何正確的找出性能問題。

            下面,我們首先來看看缺失索引。

            缺失索引

            SQL Server可以在表字段上面建立索引,從而使得Where和Join這樣的語句執(zhí)行的更快。當(dāng)查詢優(yōu)化器在優(yōu)化一個查詢的時候,它會保存一些來暗示哪些列上可能建立索引之后可能性能會更快的信息。我們可以通過動態(tài)管理視圖sys.dm_db_missing_index_details來查看,運行如下查詢

            查詢的結(jié)果如下:

            下面,我們就來稍微的解釋一下結(jié)果中主要字段的含義:

          字段名字

          說明

          DatabaseName

          告訴我們是哪一個數(shù)據(jù)庫上面存在缺失索引的問題

          equality_columns

          如果在某個字段上面進(jìn)行了相等的操作,例如Name=’Agilesharp’,在Name字段上面進(jìn)行了判等的操作,如果查詢優(yōu)化器認(rèn)為這個Name上面缺失索引,那么這個Name就會出現(xiàn)在上述查詢的結(jié)果中。

          多個字段,用逗號分割

          inquality_columns

          在某個字段上進(jìn)行了不等的操作,例如ID>1等,如果ID上面存在缺失索引,那么ID就會出現(xiàn)在這里

          Included_columns

          告訴我們那些數(shù)據(jù)列可以作為索引包含列放在索引中,從而減少書簽查找的開銷

          Statement

          告訴哪一個表上面存在缺失索引的問題

            當(dāng)然,上面的DMV查詢所得到的結(jié)果只是推薦結(jié)果,至于是否要去在相應(yīng)的列上面建立索引,還需要進(jìn)行綜合的分析,不能單靠一方面來判斷,例如,我們可以在去制定一些計劃去運行SQL Profiler去跟蹤數(shù)據(jù)庫,然后分析跟蹤的數(shù)據(jù),并且分析這個列的數(shù)據(jù)的分布情況,分析數(shù)據(jù)的密度和差異性,而且還可以進(jìn)一步的分析列的統(tǒng)計信息,然后決定是否要加索引。

            注:我也正在寫SQL Server Profiler的文章,還沒有發(fā)布,請大家耐心等待。另外SQL Server的調(diào)優(yōu)是個非常深的話題,大家可以通過我這里的一些問題在掌握一些所謂的小技巧,起到一個拋磚引玉的作用!

            說了這么多,可能大家感覺像是沒有說,感覺有點虛。確實,我也感覺這樣,因為就這分析缺失索引的問題要考慮的問題就N多。agilesharp的其他系列文章也在討論SQL Server的性能問題,這里,我們就不多說,也不把問題搞復(fù)雜了。我再送朋友一段分析的代碼,可以更好的幫助我們找到缺失索引的問題:

            上面的查詢比較不錯,按照成本進(jìn)行了分析,成本越大,就說明加了索引之后,收益就越大,可以看到如下的結(jié)果:

            然后大家加了索引之后,可以多多的測試,可以查看執(zhí)行計劃,也可以查看查詢的數(shù)據(jù)頁的讀取情況,I/O的情況:

          posted @ 2012-05-10 09:46 順其自然EVO 閱讀(387) | 評論 (0)編輯 收藏

          一次軟件測試的電話面試分享

            以下是一次典型的軟件測試電話面試分享,答案僅為個人看法,非標(biāo)準(zhǔn)答案。希望對正在找軟件測試工作的同學(xué)有所幫幫助。

            1、自我介紹

            我叫XXX,畢業(yè)于XX大學(xué)計算機(jī)科學(xué)與技術(shù)專業(yè)。畢業(yè)后進(jìn)入XX公司做了X年的軟件測試工作,主要從事XXX項目功能及性能測試的工作,熟悉TD/QTP/LoadRunner/SqlSever等,注重團(tuán)隊合作,工作認(rèn)真負(fù)責(zé),有強(qiáng)烈的責(zé)任心,喜歡專研新技術(shù);同時帶領(lǐng)過XX項目的管理工作,熟悉項目管理流程...

            有些公司可能還需要準(zhǔn)備一份英文的自我介紹。

            2、測試流程

            就說說最近的這次xxxx網(wǎng)站功能的測試流程。

            首先:得到相關(guān)文檔(需求文檔和設(shè)計文檔),理解需求和設(shè)計思想后,制定測試計劃(需評審),擬定測試策略(需評審),需要考慮到測試環(huán)境,測試時間,測試風(fēng)險等

            第二步:設(shè)計測試用例,測試策略是:先完成網(wǎng)站部分的功能點測試,然后再進(jìn)行系統(tǒng)測試(包括與其他模塊的聯(lián)調(diào)測試)。進(jìn)行測試用例的設(shè)計時,需要覆蓋到各種正常、異常處理情況。同時還包括界面測試、瀏覽器兼容性測試,易用測試及性能測試等。

            第三步:搭建測試環(huán)境,執(zhí)行測試,記錄測試缺陷

            第四步:進(jìn)行測試缺陷分析,完成測試報告編寫

            3、LoadRunner 如何優(yōu)化腳本

            ● 參數(shù)化(模擬真實的用戶選擇)

            ● 手動關(guān)聯(lián)(服務(wù)器返回的信息,例如sessionid,key的值等)

            ● 添加相應(yīng)事務(wù)的集合點(主要是用于控制并發(fā)情況)與檢查點(主要用于檢查文字是否正確和圖片是否正常顯示)

            4、說一說工作中發(fā)現(xiàn)有價值的bug

            拿xxx來說發(fā)現(xiàn)登錄模塊中,出現(xiàn)登錄延時現(xiàn)象,服務(wù)器響應(yīng)很慢,通過多次測試在分析與確認(rèn)以及和開發(fā)人員的溝通發(fā)現(xiàn)是login的**有問題。

            拿xxx來說,用于導(dǎo)航的樹型菜單,加載數(shù)據(jù)延時,通過反復(fù)測試與確認(rèn),和開發(fā)人員溝通發(fā)現(xiàn)是算法和當(dāng)初的設(shè)計加載數(shù)據(jù)導(dǎo)致的。

            5、Bug管理流程

            ● 發(fā)現(xiàn)Bug,使用缺陷管理工具提交到Bug管理庫,此時狀態(tài)時New

            ● 測試TM審核缺陷,如果確認(rèn)是問題,再分配給對應(yīng)的開發(fā)人員,設(shè)置狀態(tài)是Open

            ● 如果不是錯誤,則拒絕,設(shè)置為Declined(拒絕)狀態(tài)

            ● 開發(fā)人員查詢狀態(tài)為Open的Bug,如果不是錯誤,則置狀態(tài)為Declined;如果是Bug則修復(fù)并置狀態(tài)為Fixed;不能解決的Bug,要留下文字說明及保持Bug為Open狀態(tài);對于不能解決和延期解決的Bug,不能由開發(fā)人員自己決定,一般要通過某種會議(評審會)通過才能認(rèn)可

            ● 測試人員查詢狀態(tài)為Fixed的Bug,然后驗證Bug是否已解決,如解決置Bug的狀態(tài)為Closed,如沒有解決置狀態(tài)為Reopen

            6、軟件錯誤流程管理要點

            ● 為了保證錯誤的正確性,需要有豐富測試經(jīng)驗的測試人員驗證發(fā)現(xiàn)的錯誤是否是真正的錯誤,書寫的測試步驟是否準(zhǔn)確,可以重復(fù)。

            ● 每次對錯誤的處理都要保留處理信息,包括處理姓名,時間,處理方法,處理意見,Bug狀態(tài)。

            ● 拒絕或延期錯誤不能由程序員單方面決定,應(yīng)該由項目經(jīng)理,測試經(jīng)理和設(shè)計經(jīng)理共同決定。

            ● 錯誤修復(fù)后必須由報告錯誤的測試人員驗證后,確認(rèn)已經(jīng)修復(fù),才能關(guān)閉錯誤。

            ● 加強(qiáng)測試人員與程序員的交流,對于某些不能重復(fù)的錯誤,可以請測試人員補(bǔ)充詳細(xì)的測試步驟和方法,以及必要的測試用例

            7、談?wù)剛€人軟件測試職業(yè)發(fā)展計劃

            個人認(rèn)為測試經(jīng)驗越多,測試能力越高。所以我的職業(yè)發(fā)展是需要時間累積的,一步一步向測試經(jīng)理目標(biāo)靠近。而且我也有初步的職業(yè)規(guī)劃,前3年累積測試經(jīng)驗,不斷的更新自己改正自己,做好測試任務(wù),擴(kuò)展更多的技術(shù)。做一個全面的測試人員,我希望能夠在一個好的職位上待幾年,而且最好有一次晉升,然后就期待著下一步。不管是向上提升,還是在企業(yè)內(nèi)橫向調(diào)動,對我個人來說,我希望找到一家企業(yè),一家愿意做相互投入的企業(yè)。

            8、你有哪些優(yōu)點?

            我的學(xué)習(xí)能力和適應(yīng)環(huán)境的能力很強(qiáng),和同事們的關(guān)系處理的非常融洽,工作中很細(xì)心,投入,一旦下定決心做某事,我就要把它做好。熟話說的好:細(xì)節(jié)決定成敗,我覺得這句話在測試當(dāng)中相當(dāng)實用,往往是一個不起眼的小問題,引起了Bug.

            9、你有哪些缺點?

            我這人比較執(zhí)著,認(rèn)定的事情就不會放棄。在家的時候老媽也經(jīng)常說我蠻固執(zhí)的,在就是個性子有點急,分配給我的工作,我總想趕在第一時間盡快做好。

            10、有沒有意向去外地工作?

            我一直以來都比較獨立,不喜歡依賴于人,年輕人也需要多在外地多闖一闖。至于去哪里工作,我服從公司的調(diào)度和安排。

          11、對于加班有什么看法?

            有句話說的好加班是合理的,不加班也是合理,除特殊情況外,我都服從工作上的安排。

            12、對自己的評價?

            對于工作我比較有責(zé)任心和耐心,具備良好的職業(yè)素養(yǎng)。對于生活充滿信心和愛心,懷著一顆感恩的心,努力做好每一件事情。

            13、您所熟悉的測試用例設(shè)計方法都有哪些?

            ● 等價類劃分

            ● 邊界值分析法

            ● 錯誤推測法:基于經(jīng)驗和直覺推測程序中所有可能存在的各種錯誤, 從而有針對性的設(shè)計測試用例的方法

            ● 因果圖方法:輸入條件之間的聯(lián)系和相互組合情況,生成判定表。從而設(shè)計測試用例

            ● 比較法:比較每個版本 主要用于后期的用例

            ● 業(yè)務(wù)流程圖分析和狀態(tài)轉(zhuǎn)換分析/業(yè)務(wù)邏輯分析

            14、通過畫因果圖來寫測試用例的步驟為:

            ● 分析軟件規(guī)格說明描述中,哪些是原因(即輸入條件或輸入條件的等價類),哪些是結(jié)果(即輸出條件),并給每個原因和結(jié)果賦予一個標(biāo)識符。

            ● 分析軟件規(guī)格說明描述中的語義,找出原因與結(jié)果之間,原因與原因之間對應(yīng)的是什么關(guān)系?根據(jù)這些關(guān)系,畫出因果圖。

            ● 由于語法或環(huán)境限制,有些原因與原因之間,原因與結(jié)果之間的組合情況不可能出現(xiàn)。為表明這些特殊情況,在因果圖上用一些記號標(biāo)明約束或限制條件。

            ● 把因果圖轉(zhuǎn)換成判定表。

            ● 把判定表的每一列拿出來作為依據(jù),設(shè)計測試用例。

            15、您認(rèn)為做好測試用例設(shè)計工作的關(guān)鍵是什么?

            ● 白盒測試用例設(shè)計的關(guān)鍵是以較少的用例覆蓋盡可能多的內(nèi)部程序邏輯結(jié)果

            ● 黑盒法用例設(shè)計的關(guān)鍵同樣也是以較少的用例覆蓋模塊輸出和輸入接口。不可能做到完全測試,以最少的用例在合理的時間內(nèi)發(fā)現(xiàn)最多的問題

            16、什么是安全性測試?

            全測試是在IT軟件產(chǎn)品的生命周期中,特別是產(chǎn)品開發(fā)基本完成到發(fā)布階段,對產(chǎn)品進(jìn)行檢驗以驗證產(chǎn)品符合安全需求定義和產(chǎn)品質(zhì)量標(biāo)準(zhǔn)的過程 。

            ● 用戶認(rèn)證安全

            ● 系統(tǒng)網(wǎng)絡(luò)安全

            ● 數(shù)據(jù)庫安全

            17、什么是集成測試?

            在單元測試的基礎(chǔ)上,將所有模塊按照設(shè)計要求組裝成為子系統(tǒng)或系統(tǒng),進(jìn)行集成測試。英文一些模塊雖然能夠單獨工作,但并不能保證連接起來也能正常的工作。程序在某些局部反映不出來的問題,在全局上很可能暴露出來,影響功能的實現(xiàn)。

            集成測試應(yīng)該考慮以下問題:

            ● 在把各個模塊連接起來的時候,穿越模塊接口的數(shù)據(jù)是否會丟失;

            ● 各個子功能組合起來,能否達(dá)到預(yù)期要求的父功能;

            ● 一個模塊的功能是否會對另一個模塊的功能產(chǎn)生不利的影響;

            ● 全局?jǐn)?shù)據(jù)結(jié)構(gòu)是否有問題;

            ● 單個模塊的誤差積累起來,是否會放大,從而達(dá)到不可接受的程度

            18、你有什么問題要問的?

            可以問一問該公司的測試流程,個人職業(yè)發(fā)展方向,公司產(chǎn)品項目等等。

          posted @ 2012-05-10 09:21 順其自然EVO 閱讀(3174) | 評論 (0)編輯 收藏

          僅列出標(biāo)題
          共394頁: First 上一頁 328 329 330 331 332 333 334 335 336 下一頁 Last 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 曲沃县| 叙永县| 永善县| 南京市| 高安市| 左云县| 那曲县| 塔城市| 淳安县| 郧西县| 柳州市| 黑水县| 元谋县| 泸定县| 长顺县| 拉萨市| 甘洛县| 神农架林区| 泾源县| 丹凤县| 琼结县| 九龙坡区| 招远市| 岢岚县| 普安县| 建宁县| 中超| 安岳县| 东乡县| 黔西县| 伊金霍洛旗| 黑龙江省| 都江堰市| 偏关县| 青冈县| 灵宝市| 忻城县| 绥阳县| 田东县| 江油市| 田林县|