table

          監(jiān)控和剖析數(shù)據(jù)庫操作 -- P6Spy、SQL Profiler、IronTrack SQL 使用簡(jiǎn)介

          本文介紹如何在應(yīng)用程序中利用 P6Spy、SQL Profiler、IronTrack SQL 工具來對(duì)數(shù)據(jù)庫操作進(jìn)行監(jiān)控與剖析,從中發(fā)現(xiàn)應(yīng)用系統(tǒng)存在的性能瓶頸,得到相關(guān)的優(yōu)化建議并最終找到相應(yīng)的解決辦法。

          幾乎 80% - 85% 的數(shù)據(jù)庫性能問題是由于應(yīng)用數(shù)據(jù)庫的設(shè)計(jì)或者應(yīng)用程序本身的代碼所引起的。因此良好的事務(wù)處理能力需要在設(shè)計(jì)應(yīng)用程序的時(shí)候,在設(shè)計(jì)數(shù)據(jù)庫的時(shí)候就考慮到性能和伸縮性。

          ---- DB2 Magazine

          在我們 Java 開發(fā)應(yīng)用程序的過程中,難免會(huì)碰到系統(tǒng)的性能問題,特別在企業(yè)應(yīng)用的開發(fā)過程中,都會(huì)與數(shù)據(jù)庫進(jìn)行打交道。當(dāng)我們碰到數(shù)據(jù)庫性能時(shí),最有效的就是直接跟蹤每一個(gè) SQL 語句的執(zhí)行情況,SQL 語句的優(yōu)化、索引的優(yōu)化往往也是最容易取得最直接的效果的。

          下面,我們首先開始介紹 P6Spy 這個(gè)剖析工具,看它是如何無侵入性地進(jìn)行數(shù)據(jù)庫操作的監(jiān)控與剖析。

          P6Spy

          P6Spy 是一個(gè)可以用來在應(yīng)用程序中攔截和修改數(shù)據(jù)操作語句的開源框架。通過 P6Spy 我們可以對(duì) SQL 語句進(jìn)行攔截,相當(dāng)于一個(gè) SQL 語句的記錄器,這樣我們可以用它來作相關(guān)的分析,比如性能分析。P6Spy 用 Log4J 來記錄 JDBC 調(diào)用的日記信息。

          自從 2003 年 11 月 30 日 P6Spy 版本 1.3 發(fā)布后,已經(jīng)被下載超過 19,000 次了。P6Spy 支持 WebSphere、WebLogic、JBoss、Resin 和 Tomcat 等絕大多數(shù)的應(yīng)用服務(wù)器。

          使用步驟

          首先,你的應(yīng)用系統(tǒng)應(yīng)當(dāng)是基于數(shù)據(jù)庫的,然后你需要去獲取 P6Spy 相關(guān)的文件(在 參考資源 中可以找到下載鏈接,您可以直接下載軟件包)。下面介紹 P6Spy 的安裝與使用的詳細(xì)操作過程:

          1. 下載 P6Spy 的文件包,也可以下載它的源文件包來研究;
          2. 把 P6Spy 的 jar 包 p6spy.jar 放到 CLASSPATH 中,如果是 Web 應(yīng)用程序則放在 YourWebApp/WEB-INF/lib/ 目錄下;
          3. 把 spy.properties 放到 CLASSPATH 目錄下,如果是 Web 應(yīng)用程序放在 YourWebApp/WEB-INF/classess/ 目錄下,注意不是 lib/ 目錄
          4. 修改你應(yīng)用系統(tǒng)中的數(shù)據(jù)庫驅(qū)動(dòng)名稱為 P6Spy 的驅(qū)動(dòng)程序名稱 com.p6spy.engine.spy.P6SpyDriver 其它的全部使用默認(rèn)值,暫時(shí)先都不用修改;
          5. 打開配置文件 spy.properties 文件,找到 realdriver,把它的值改為你的應(yīng)用系統(tǒng)的真正的數(shù)據(jù)庫驅(qū)動(dòng)名稱;
          6. 運(yùn)行你的應(yīng)用程序或 Web 應(yīng)用程序,可以在 spy.log 里看到 P6Spy 監(jiān)測(cè)到的 SQL 詳細(xì)的執(zhí)行與操作的記錄信息了,包含有完整的 SQL 執(zhí)行參數(shù)。

          P6Log 與 P6Outage

          在 P6Spy 發(fā)布包中,它包含 P6Log 和 P6Outage 兩個(gè)模塊:

          1. P6Log

            P6Log 是用來攔截和記錄任務(wù)應(yīng)用程序的 JDBC 語句的。這個(gè)功能對(duì)于開發(fā)者監(jiān)控 EJB 服務(wù)器上的 SQL 語句執(zhí)行情況尤其有用,可以讓開發(fā)者完成盡可能高效的代碼。同時(shí) P6Spy 的部署是極其簡(jiǎn)單的,而且根本不需要更改任何一行代碼,即對(duì)現(xiàn)有的應(yīng)用是無侵入性的。

            realdriver= (your driver)       (你的實(shí)際 JDBC 驅(qū)動(dòng)程序名稱)
                            executionthreshold=整數(shù)時(shí)間     (以毫秒為單位)
                            

          2. P6Outage

            P6Outage 專門用來檢測(cè)和記錄執(zhí)行時(shí)間比較長的 SQL 語句,P6Outage 只記錄超過配置條件里時(shí)間的那些信息,并對(duì)可能影響到數(shù)據(jù)庫的運(yùn)行效率減小到最低。

            #outagedetection=true|false    (是否記錄較長時(shí)間運(yùn)行的語句)
                            #outagedetectioninterval=整數(shù)時(shí)間 (以秒為單位)
                            

          架構(gòu)原理

          簡(jiǎn)單地講,我們可以認(rèn)為 P6Spy 就是一個(gè)代理(Proxy),它只做了一層對(duì) JDBC 驅(qū)動(dòng)的攔截,然后轉(zhuǎn)發(fā)出去,這樣的設(shè)計(jì)與實(shí)際的應(yīng)用程序沒有任何的耦合性,除了在配置中將驅(qū)動(dòng)程序改成 P6Spy 的攔截驅(qū)動(dòng)外,程序其他地方并不需要做任何的改變。這層攔截器除了可能會(huì)給系統(tǒng)帶來略微的性能下降外,對(duì)程序其他方面沒有任何的影響。而相對(duì)于這一點(diǎn)點(diǎn)的性能下降,在開發(fā)環(huán)境中對(duì)于開發(fā)人員來說是無法感覺到,相比它所帶來的好處,完全可以忽略不計(jì)。


          圖 1. P6Spy 對(duì)數(shù)據(jù)庫進(jìn)行攔截監(jiān)控的處理過程
          圖 1. P6Spy 對(duì)數(shù)據(jù)庫進(jìn)行攔截監(jiān)控的處理過程

          問題與解決

          如果在你的應(yīng)用程序啟動(dòng)后,卻在 spy.log 文件中發(fā)現(xiàn)了如下的提示信息,那就是驅(qū)動(dòng)程序加載先后的問題了。

          <你的程序的數(shù)據(jù)庫驅(qū)動(dòng)名稱> is a real driver in spy.properties, but it has
                      been loaded before p6spy.  p6spy will not wrap these connections.  Either
                      prevent the driver from loading, or try setting'deregisterdrivers' to true in
                      spy.properties
                      

          請(qǐng)把 spy.properties 配置文件里的 deregisterdrivers=false 改為 deregisterdrivers=true,重新運(yùn)行即可。

          這是因?yàn)橛行?yīng)用系統(tǒng)中會(huì)先于 P6Spy 加載了真正的數(shù)據(jù)庫的驅(qū)動(dòng)程序,導(dǎo)致 P6Spy 無法監(jiān)控到,設(shè)置 deregisterdriverstrue,是顯式地把真正的數(shù)據(jù)庫的驅(qū)動(dòng)程序進(jìn)行反注冊(cè)掉,而采用 P6Spy 的驅(qū)動(dòng)程序。

          配置參數(shù)及相關(guān)意義

          下表列出了 spy.properties 配置文件中的各配置項(xiàng)的名稱、默認(rèn)值及其意義和相關(guān)注意事項(xiàng):

          配置項(xiàng)名稱 默認(rèn)值 配置項(xiàng)意義及相關(guān)注意事項(xiàng)
          module.log com.p6spy.engine.logging. P6LogFactory 用來攔截和記錄任務(wù)應(yīng)用程序的 JDBC 語句。若無配置或注釋掉則無此功能。
          module.outage com.p6spy.engine.outage. P6OutageFactory 檢測(cè)和記錄執(zhí)行時(shí)間比較長的 SQL 語句。若無配置或注釋掉則無此功能。
          realdriver   真正的應(yīng)用系統(tǒng)使用的數(shù)據(jù)庫驅(qū)動(dòng)程序名稱。
          realdriver2   真正的應(yīng)用系統(tǒng)使用的第二種備用數(shù)據(jù)庫驅(qū)動(dòng)程序名稱。
          realdriver3   真正的應(yīng)用系統(tǒng)使用的第三種備用數(shù)據(jù)庫驅(qū)動(dòng)程序名稱。
          deregisterdrivers false 顯示地把真正的數(shù)據(jù)庫的驅(qū)動(dòng)程序進(jìn)行反注冊(cè)掉。取值 true| false
          executionthreshold   P6Log 模塊執(zhí)行時(shí)間設(shè)置,整數(shù)值 (以毫秒為單位),只有當(dāng)超過這個(gè)時(shí)間才進(jìn)行記錄 Log。
          outagedetection false P6Outage 模塊是否記錄較長時(shí)間運(yùn)行的語句。取值 true| false
          outagedetectioninterval   P6Outage 模塊執(zhí)行時(shí)間設(shè)置,整數(shù)值 (以秒為單位)),只有當(dāng)超過這個(gè)時(shí)間才進(jìn)行記錄 Log。
          filter false 是否過濾 Log,取值 true| false
          include   過濾 Log 時(shí)所包含的表名列表,以逗號(hào)分隔。
          exclude   過濾 Log 時(shí)所排除的表名列表,以逗號(hào)分隔。
          sqlexpression   過濾 Log 時(shí)的 SQL 表達(dá)式名稱
          autoflush true 是否自動(dòng)刷新。取值 true| false
          dateformat   設(shè)置時(shí)間的格式,也就是用 Java 的 SimpleDateFormat 程序。
          includecategories   顯示指定過濾 Log 時(shí)包含的分類列表,取值為 error,info,batch,debug,statement,commit,rollback,result 的各種組合。
          excludecategories   顯示指定過濾 Log 時(shí)排隊(duì)的分類列表,取值同上。
          stringmatcher   使用正則表達(dá)式來過濾 Log,取值為 com.p6spy.engine.common.GnuRegexMatcher 和 com.p6spy.engine.common.JakartaRegexMatcher
          stacktrace false 打印堆棧跟蹤信息。取值 true| false
          stacktraceclass   如果 stacktrace=true,則可以指定具體的類名來進(jìn)行過濾。
          reloadproperties false 監(jiān)測(cè)屬性配置文件是否進(jìn)行重新加載。取值 true| false
          reloadpropertiesinterval 60 屬性配置文件重新加載的時(shí)間間隔,以秒為單位。
          useprefix false 是否加上前綴,設(shè)置為 true,會(huì)加上 p6spy: 作為前綴。取值 true| false
          appender com.p6spy.engine.logging. appender.FileLogger 指定 Log 的 appender,與 Log4J 有點(diǎn)同義,取值:com.p6spy.engine.logging.appender.Log4jLogger、com.p6spy.engine.logging.appender.StdoutLogger 和 com.p6spy.engine.logging.appender.FileLogger
          logfile spy.log 指定 Log 的文件名,任何適于操作系統(tǒng)的文件。
          append true 指定是否每次是增加 Log,設(shè)置為 false 則每次都會(huì)先進(jìn)行清空。取值 true| false
          log4j.appender.STDOUT org.apache.log4j.ConsoleAppender 當(dāng) appender 為 log4j 時(shí)采用的配置,配置如同 Log4J 的相關(guān)配置。
          log4j.appender.STDOUT.layout org.apache.log4j.PatternLayout 同上
          log4j.appender.STDOUT. layout.ConversionPattern p6spy - %m%n 同上
          log4j.logger.p6spy INFO,STDOUT Log 級(jí)別的設(shè)置,取值同 Log4J 的配置
          realdatasource   設(shè)置數(shù)據(jù)源 DataSource 的配置名稱。
          realdatasourceclass   設(shè)置數(shù)據(jù)源 DataSource 的類的全稱。
          realdatasourceproperties   設(shè)置數(shù)據(jù)源 DataSource 的屬性,以分號(hào)分隔。
          jndicontextfactory   設(shè)置 JNDI 數(shù)據(jù)源的 NamingContextFactory。
          jndicontextproviderurl   設(shè)置 JNDI 數(shù)據(jù)源的提供者的 URL。
          jndicontextcustom   設(shè)置 JNDI 數(shù)據(jù)源的一些定制信息,以分號(hào)分隔。




          回頁首


          SQL Profiler

          SQL Profiler 是一個(gè)由 Jahia.org 提供的基于 P6Spy 引擎的快速剖析工具,用來統(tǒng)計(jì) SQL 查詢語句以便了解哪里是性能瓶頸,在哪里創(chuàng)建索引或者采取相應(yīng)的辦法才能提高效率,并且能根據(jù) SQL 查詢語句的情況幫你生成合適的索引腳本。

          這個(gè)小工具可以實(shí)時(shí)地顯示數(shù)據(jù)庫查詢的情況,通過集成的 SQL 解析器,在訪問大多數(shù)表與列上面建立統(tǒng)計(jì)分析,并生成索引腳本。當(dāng)然,其它的信息也會(huì)進(jìn)行收集和顯示,比如:?jiǎn)蝹€(gè)數(shù)據(jù)庫請(qǐng)求的時(shí)間、一類請(qǐng)求的時(shí)間以及所有請(qǐng)求的時(shí)間。因此,可以有效地通過視圖的排序來檢測(cè)數(shù)據(jù)的性能問題所在。這個(gè)工具對(duì)于大量的需要進(jìn)行分析的請(qǐng)求是非常有用的,而不是人工一個(gè)個(gè)地去做分析。當(dāng)你需要知道比如對(duì)相同的表和列進(jìn)行訪問但是采用不同的查詢值時(shí),這種分組的查詢可以用建立在 ANTLR 上的 SQL 解析器進(jìn)行分析。

          使用步驟

          首先,你的應(yīng)用系統(tǒng)同樣也應(yīng)當(dāng)是基于數(shù)據(jù)庫的,然后你需要去獲取 SQL Profiler 相關(guān)的文件(在 參考資源 中可以找到下載鏈接,您可以直接下載軟件包)。下面介紹 SQL Profiler 的安裝與使用的詳細(xì)操作過程:

          1. 下載 SQL Profiler 的文件包進(jìn)行安裝;
          2. 把 p6spy.jar 及 sqlprofiler.jar 放到 CLASSPATH 中,如果是 Web 應(yīng)用程序則放在 YourWebApp/WEB-INF/lib/ 目錄下;
          3. 把 spy.properties 放到 CLASSPATH 目錄下,如果是 Web 應(yīng)用程序就放在 YourWebApp/WEB-INF/classess/ 目錄下,注意不是 lib/ 目錄;
          4. 修改你應(yīng)用系統(tǒng)中的數(shù)據(jù)庫驅(qū)動(dòng)名稱為 P6Spy 的驅(qū)動(dòng)程序名稱 com.p6spy.engine.spy.P6SpyDriver 其它的全部使用默認(rèn)值,暫時(shí)不用修改;
          5. 打開 spy.properties 文件,把 realdriver 的值改為你的程序的數(shù)據(jù)庫驅(qū)動(dòng)名稱;
          6. 注意要先運(yùn)行 java -jar sqlprofiler.jar 來啟動(dòng) SQL Profiler,并成功看到啟動(dòng)界面;
          7. 然后再啟動(dòng)你的應(yīng)用程序或服務(wù)器,并開始進(jìn)行正常的系統(tǒng)請(qǐng)求處理操作;
          8. 這樣就可以在 SQL Profiler 圖形化的界面上看到結(jié)果并進(jìn)行分析了。

          分析結(jié)果

          經(jīng)過一段時(shí)間的系統(tǒng)運(yùn)行后,點(diǎn)擊 Pause 按鈕停止攔截,可以得到分析結(jié)果如下圖:


          圖 2. SQL Profiler 的分析結(jié)果 Profiler 視圖
          圖 2. SQL Profiler 的分析結(jié)果 Profiler 視圖

          接著,可以切換到 Loggers 視圖,這是 Lgger 視圖的信息:


          圖 3. SQL Profiler 的分析結(jié)果 Logger 視圖
          圖 3. SQL Profiler 的分析結(jié)果 Logger 視圖

          當(dāng)然,也可以切換到 Analysis 視圖,這是 Analysis 視圖的分析結(jié)果信息:


          圖 4. SQL Profiler 的分析結(jié)果 Analysis 視圖
          圖 4. SQL Profiler 的分析結(jié)果 Analysis 視圖

          在經(jīng)過分析后,我們可以直接通過 SQLProfiler 提交的保存按鈕,直接導(dǎo)出應(yīng)當(dāng)進(jìn)行數(shù)據(jù)庫優(yōu)化的建議的索引腳本,通過查看索引腳本,我們可以看到創(chuàng)建索引的詳細(xì) SQL 腳本,這樣,我們就可以非常方便地進(jìn)行數(shù)據(jù)庫調(diào)優(yōu)了。

          問題與解決

          最后一個(gè)需要注意的問題就是需要先啟動(dòng) SQLProfiler,然后再啟動(dòng)應(yīng)用程序或者 Tomcat 等應(yīng)用服務(wù)器。這是因?yàn)?SQLProfiler 默認(rèn)使用的是 Log4j 的 SocketAppender,所以要先啟動(dòng)。否則,會(huì)因你的應(yīng)用程序或應(yīng)用服務(wù)器中的 Web 應(yīng)用之類的因連接不到 Socket 的服務(wù)器(SQLProfiler 相當(dāng)于 Socket 的服務(wù)器)而發(fā)生錯(cuò)誤,可以通過 SQL Profiler 控制界面最下面的連接狀態(tài)就可以知道是否有程序連接上來。


          圖 5. SQL Profiler 處于非連接狀態(tài)
          圖 5. SQL Profiler 處于非連接狀態(tài)

          圖 6. SQL Profiler 處于連接狀態(tài)
          圖 6. SQL Profiler 處于連接狀態(tài)




          回頁首


          IronTrack SQL

          IronEye,一個(gè)專注于 JDBC 性能的監(jiān)控和測(cè)試的開源項(xiàng)目,它包含有三個(gè)工具:IronEye SQL,IronEye Cache,IronTrack SQL。其中,IronEye SQL 用于監(jiān)測(cè) Java 應(yīng)用和數(shù)據(jù)庫服務(wù)器之間查詢開銷的時(shí)間,診斷在性能方面是否存在著相關(guān)問題,讓開發(fā)人員在測(cè)試之前就能發(fā)現(xiàn)問題。IronEye 于 2003 年 10 月 1 日開始基于 Apache Software License 發(fā)布。

          IronEye SQL 這個(gè)輕量級(jí)的 Java 工具提供所有流動(dòng)在數(shù)據(jù)庫與應(yīng)用程序之間的 SQL 統(tǒng)計(jì)信息并用多張圖表展現(xiàn),可以快速優(yōu)化程序的性能。

          IronGrid 相對(duì)于 Continuous Integration 提出了 Continuous Performance 的概念,即在項(xiàng)目開發(fā)過程中隨時(shí)關(guān)注性能問題,而不是傳統(tǒng)的出了問題再解決的方案。

          IronGrid 在應(yīng)用程序?qū)?shù)據(jù)庫的操作上的 Continuous Performance 是通過 IronTrack SQL 進(jìn)行體現(xiàn)的。IronTrack SQL 能通過對(duì) JDBC 的包裝來攔截應(yīng)用程序?qū)?shù)據(jù)庫的請(qǐng)求,完成性能監(jiān)控。IronTrack SQL 的好處在于不需要修改任何代碼或者在數(shù)據(jù)庫端安裝任何程序,只需要在測(cè)試時(shí)把依賴的 JDBC 替換就可以了。

          使用步驟

          首先,你的應(yīng)用系統(tǒng)同樣也應(yīng)當(dāng)是基于數(shù)據(jù)庫的,然后你需要去獲取 IronTrack SQL 相關(guān)的文件(在 參考資源 中可以找到下載鏈接,您可以直接下載軟件包)。下面介紹 IronTrack SQL 的安裝與使用的詳細(xì)操作過程:

          1. 下載 IronTrack SQL 的文件包進(jìn)行安裝;
          2. 把 irontracksql.jar, p6spy.jar 和 log4j-1.2.8.jar 放到 CLASSPATH 中,如果是 Web 應(yīng)用程序則放在 YourWebApp/WEB-INF/lib/ 目錄下;
          3. 把 spy.properties 放到 CLASSPATH 目錄下,如果是 Web 應(yīng)用程序就放在 YourWebApp/WEB-INF/classess/ 目錄下,注意不是 lib/ 目錄;
          4. 修改你程序的數(shù)據(jù)庫驅(qū)動(dòng)名稱為 P6Spy 的驅(qū)動(dòng)程序名稱 com.p6spy.engine.spy.P6SpyDriver 其它的都不用更改;
          5. 打開配置文件 spy.properties 文件,找到 realdriver,把它的值改為你的應(yīng)用系統(tǒng)的真正的數(shù)據(jù)庫驅(qū)動(dòng)名稱;
          6. 設(shè)置監(jiān)聽端口號(hào) monitorport=2000
          7. 先運(yùn)行 java -jar irontracksql.jar 來啟動(dòng) IronTrack SQL;
          8. 再啟動(dòng)你的應(yīng)用程序或服務(wù)器;
          9. 可以在 IronTrack SQL 圖形化的界面上看到結(jié)果并進(jìn)行分析了。

          連接設(shè)置

          點(diǎn)擊“Config”按鈕就可以設(shè)置主機(jī)名、端口與刷新的時(shí)間(毫秒為單位)。根據(jù)你的服務(wù)器與端口的不同而進(jìn)行相應(yīng)地改變,下面以本地和 2000 端口,刷新時(shí)間為 500 毫秒為示例。設(shè)置完成后,確定,點(diǎn)擊“Connect”就可以連接應(yīng)用系統(tǒng)并進(jìn)行監(jiān)測(cè)與分析了,當(dāng)要停止分析時(shí),只要點(diǎn)擊“Disconnect”按扭即可立刻停止分析了。

          在分析的過程中,我們可以根據(jù)需要點(diǎn)擊“Purge”按鈕,它可以清除目前所監(jiān)測(cè)到的內(nèi)容,然后重新進(jìn)行記錄監(jiān)測(cè)信息,很方便地進(jìn)行重新開始。


          圖 7. IronTrack SQL 連接示例
          圖 7. IronTrack SQL 連接示例

          分析結(jié)果

          經(jīng)過一段時(shí)間的系統(tǒng)運(yùn)行后,我們可以直接得到分析的結(jié)果與相應(yīng)的圖形分析示例。相關(guān)的信息顯示如下:


          圖 8. IronTrack SQL 分析結(jié)果
          圖 8. IronTrack SQL 分析結(jié)果
          • Count 列顯示 SQL 語句的調(diào)用次數(shù);
          • Avg Time 列顯示 SQL 語句的執(zhí)行平均時(shí)間;
          • Max Time 列顯示 SQL 語句花費(fèi)的最高時(shí)間;
          • SQL 列顯示真正執(zhí)行的 SQL 語句內(nèi)容。

          同時(shí)也可以通過設(shè)置過濾條件來顯示指定條件的結(jié)果,比如:只關(guān)注平均調(diào)用次數(shù)大于 100 次 的結(jié)果。點(diǎn)擊“Filtering”左邊的小三角圖標(biāo),可以顯示如下的過濾條件設(shè)置欄目:


          圖 9. IronTrack SQL 設(shè)置相關(guān)的過濾條件
          圖 9. IronTrack SQL 設(shè)置相關(guān)的過濾條件

          設(shè)置完成后,點(diǎn)擊“Apply Filter”按鈕即可以獲取所需要的相關(guān)結(jié)果了。這樣可以更加方便地集中精力進(jìn)行所需要的內(nèi)容分析,可以更加方便快速地定位到問題的所在之處,然后進(jìn)行解決。





          回頁首


          總結(jié)

          通過使用 P6Spy、SQL Profiler、IronTrack SQL 工具,我們可以無侵入已有的應(yīng)用系統(tǒng)而有效地進(jìn)行數(shù)據(jù)庫操作的監(jiān)控與剖析,為發(fā)現(xiàn)系統(tǒng)的性能瓶頸,尋找系統(tǒng)的性能調(diào)優(yōu)提供了相當(dāng)便利的方法。



          參考資料

          學(xué)習(xí)

          獲得產(chǎn)品和技術(shù)

          posted on 2009-08-12 14:48 小卓 閱讀(203) 評(píng)論(0)  編輯  收藏 所屬分類: datebase

          主站蜘蛛池模板: 平原县| 益阳市| 当涂县| 泰州市| 镇巴县| 疏附县| 京山县| 晋城| 宜昌市| 聂拉木县| 万安县| 安福县| 沭阳县| 清苑县| 涟水县| 高密市| 龙门县| 高州市| 长兴县| 宽甸| 紫金县| 金溪县| 吴桥县| 乌苏市| 北流市| 石林| 双牌县| 曲沃县| 老河口市| 芮城县| 珠海市| 桓仁| 海林市| 扎囊县| 大化| 乌拉特前旗| 高清| 五原县| 集安市| 洪泽县| 开原市|