<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/

    如何調試CSS的跨瀏覽器樣式bug

    首先要做的是挑選一個好的瀏覽器。我的選擇是Chrome,因為它擁有強大的調試工具。當我在Chrome上完成調試后,我會接著在Safari或者Firefox上調試。
      如果在這些“好的”瀏覽器上沒有達到期望的效果,很有可能是代碼本身違背了CSS規則。不要試圖使用hack方法來解決在這些“好的”瀏覽器上出現的問題,而是應該找出問題的原因。通常我會檢查以下可能的BUG出處:
      HTML代碼解釋 - 你是否忘記閉合一個標簽? 你是否用一個inline元素包住一個block元素? 違背標準的代碼可能在不同的瀏覽器上被解釋呈現成不同的效果。
      使用CSS lint工具檢查CSS代碼。留意那些檢查出來的Errors。多數情況下,Errors比Warnings更容易引發跨瀏覽器差異。
      忘記使用reset樣式表,而是依靠于(不同的)瀏覽器默認的CSS樣式。
      瀏覽器支持性的差異。你是否使用了高級CSS3屬性或者HTML5元素?查看瀏覽器支持性文檔從而確保所有你的受眾的瀏覽器都被涵蓋。你需要設計“功能降級”來支持老式的瀏覽器。比如,把陰影邊框降級成邊框,或者把圓角降級成方塊。
      在不該有空格的地方加上了空格,margin可能因此呈現得詭異。
      使用了絕對定位,可是沒有設置垂直和水平偏移。這種情況下,絕對定位的元素將被呈現在跟position:static一樣的位置上。但是,如果你嘗試更改它的top,right,bottom或者left值,這個元素將馬上“跳”到參照于它最近的相對定位的父元素的位置。
      按照“不尋常”的方式組合了不同display方式的元素。比如,W3C標準并沒有說當一個table-cell緊鄰一個浮動元素時應該是怎樣的layout。因此,這樣寫的代碼并不是錯誤的,但可能會導致跨瀏覽器呈現不同效果的BUG。
      空格是否影響了layout。你應該不想讓排版樣式依賴于空格。
      小數點像素值會導致跨瀏覽器的不同效果。
      接下來正文來了
      最重要的需要記住的就是,W3C標準并沒有定義錯誤的行為。因此,如果你沒有按照規范寫,那么可能會導致跨瀏覽器不同效果;如果你組合“奇怪的”屬性(例如margin和inline element),那么也可能會導致跨瀏覽器不同效果bug。
      Display
      我認為書寫CSS就像在選擇一段旅程。你需要作出一些決定.比如你要首先選擇使用不同display方式的元素:block,inline,inline-block和table。當你選擇好以后,你可以使用一些具體的方法來改變其實際的顯示。
      塊元素應該使用margin,padding,height和width。然而line-height不適用。
      行內元素應該使用line-height,vertical align和空格符。然而margin,padding,height和width不適用。
      首先,表格有垂直和水平排列方式。其次,如果你遺漏了表格中的某元素,整個表格可能會有詭異的顯示。最后,margin不適用與表格的行和列,padding不適用與表格和表格的行。
      Positioning
      如果你選擇使用塊級元素,接下來你需要選擇position方式:
      Float - 如果你使用了float,那么這個元素就變成了塊級元素,而之前作用于該元素的vertical-align和line-height屬性都將失效。
      Absolute - 相對于最近的相對定位的父節點來計算偏移量。當父節點和兄弟節點改變時,絕對定位的元素并不會導致reflow。這個特性有利于制作動畫效果。但是,如果使用了絕對定位和動態更改內容將可能會導致顯示問題,一個典型的例子是絕對定位的圓角框。
      Static – 默認的position方式。
      Fixed - 元素位置相對于瀏覽器窗口。不常使用的方式。
      Relative – 通常對于該元素樣式不影響。只是其下屬的絕對定位的子節點將相對于該節點計算偏移。
      在這里我就不列舉所有的display和position組合了。總之,有兩件事情需要注意:
      對于我選擇的display和position方式,其他的屬性(比如margin,line-height)是不是適合?
      兄弟節點的position方式是不是契合?
      比如,float,table-cell和行內元素組合在一起是否合適?瀏覽器將如何解釋渲染?在W3C標準里有沒有定義?如果沒有,那么可能就有出現跨瀏覽器bug的風險。當然,這樣的組合并不是不可以,但你要想清楚為什么要這樣做,以及做好足夠的跨瀏覽器測試
      Internet Explorer
      當你解決了在“好的”瀏覽器上出現的問題后,現在應開始著手IE平臺。我的建議是從你希望支持的最老版本的IE開始,因為很多老版本IE上的問題在新版本中延續出現。
      就算對于IE,你也應該嘗試找出問題而不是依賴于使用hack方法。盲目使用*和_的hack方法就像在一個返回錯誤值的函數中加入修正量(如下),而不是找出其中的算法性錯誤。
      return result + 4;
      當然,有時候在IE6和IE7里面使用hack是必要的。對于IE8,通常只在需要兼容CSS3的地方使用hack。通常情況下,在IE6/7里需要使用hack的地方有:
      hasLayout問題,使用zoom:1
      相對定位導致元素消失
      3px浮動BUG
      被撐大的容器的浮動錯誤,可是經常被overflow:hidden碰巧的掩飾了。
      還有一些不太常見的需要使用hack的情況,比如當兩個浮動元素中間有comment代碼時將會觸發重復內容bug。對于只在IE中出現的css問題,我的建議是仔細描述你所看見的,并在google中搜索相應的解決方法。在你找到bug原因前,不要盲目使用hack掩飾它。IE自帶的調試工具很糟糕,所以可能你需要給元素增加背景色來方便你查看頁面上真實的排版。
    實現解決方案
      當你找到bug的原因并且知道解決方法后,你同時也應該知道如何在修改代碼時不破壞已有的正常效果的代碼。下面是我的建議:
      1. 依賴樣式級聯
      2. 使用針對特定瀏覽器的前綴
      3. 使用針對IE6/7的*和_
      4. 不要使用針對IE8的\9
      5. 知道什么時候該放棄針對IE的hack
      6. 不要對最新版本的Firefox,Chrome,Safari使用任何hack
      1. 依賴樣式級聯
      首先,在任何可能的情況下都盡量依靠樣式級聯。瀏覽器總是采取他們能夠讀懂的最后聲明的樣式。所以,你應該從針對老版本瀏覽器的樣式開始書寫,這樣個瀏覽器就能讀懂和使用它能讀懂的最后的樣式。例如:
      .foo{
      background-color: #ccc; /* older browsers will use this */
      background-color: rgba(0,0,0,0.2); /* browsers that understand rgba will use this */
      }
      2. 使用針對特定瀏覽器的前綴
      使用針對特定瀏覽器的前綴,尤其對于還未被廣泛采用的屬性適用。例如:
      .foo{
      background: #1e5799; /* Old browsers */
      background: -moz-linear-gradient(top, #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%); /* FF3.6+ */
      background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(50%,#2989d8), color-stop(51%,#207cca), color-stop(100%,#7db9e8)); /* Chrome,Safari4+ */
      background: -webkit-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Chrome10+,Safari5.1+ */
      background: -o-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Opera 11.10+ */
      background: -ms-linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* IE10+ */
      background: linear-gradient(top, #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* W3C */
      }
      注意,這套代碼里有兩個針對不同版本webkit的語法。前綴代碼的順序同樣應該從針對老版本瀏覽器開始書寫(參照第一條)。
      如果有一個W3C標準定義的語法,你應該把它放在最后(例如上述代碼最后一行)。這樣隨著瀏覽器開始支持這些新特性的標準語法,你的代碼也能夠穩健表現。
      3. 使用針對IE6/7的*和_對于舊版本IE特有的bug,使用*和_來彌補。比如:
      .clearfix {
      overflow: hidden; /* new formatting context in better browsers */
      *overflow: visible; /* protect IE7 and older from the overflow property */
      *zoom: 1; /* give IE hasLayout, a new formatting context equivalent */
      }
      所有的IE hack都針對于某版本和其之前的所有瀏覽器,比如:
      _ 針對IE6和更早版本
      * 針對IE7和更早版本
      \9 針對IE8和更早版本 (注意,IE9在某些CSS屬性上同樣對于這個hack敏感)
      所以,hack代碼的順序同樣也應該從針對老版本瀏覽器開始書寫(參照第一條)。
      4. 不要使用針對IE8的\9
      我從來不會使用\9來解決IE8里面出現的樣式bug。我只會在彌補瀏覽器支持性上使用\9來做“降級”處理。比如我使用了box-shadow(在更先進的瀏覽器上正常),可是在IE8下很難看,因此我使用了\9來增加了一個新border。這種情況不能依靠樣式級聯(參照第一條)來處理,因為這是增加一個新樣式,而不是修改一個已有的樣式。
      5. 知道什么時候該放棄針對IE的hack
      不要試追求在IE中得到一模一樣的效果。你是否愿意浪費額外的HTTP請求,繁雜的HTML/JS/CSS代碼段為了實現在IE6-8中同樣看到圓角框效果?對于我個人來說,我的答案是“不會”。
      你應該知道什么時候放棄針對某功能的hack。例如,不要使用filter去模擬CSS3里的漸變效果,那樣會導致性能問題和排版bug。最簡單的辦法是,壓根不要寄希望你的網頁在所有瀏覽器中都表現得一模一樣。對于IE 6-8的用戶,最好的辦法就是給他們一個簡單化的用戶體驗(注意,是簡單化而不是殘缺)。
      下述糟糕的代碼就是使用filter去模擬CSS3里的gradient:
      .foo {
      filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#1e5799', endColorstr='#7db9e8',GradientType=0 ); /* IE6-9 */
      }
      6. 不要對最新版本的Firefox,Chrome,Safari使用任何hack
      對于Firefox,Chrome,Safari上的樣式bug,最好的辦法是仔細檢查,很有可能這是因為你的代碼違背了CSS的規則。

    posted @ 2014-09-17 09:46 順其自然EVO 閱讀(327) | 評論 (0)編輯 收藏

    XAMPP和Bugfree詳細教程

     一、XAMPP安裝配置
      xampp是一款跨平臺的集成 apache + mysql + php環境,是的配置AMP服務器變得簡單輕松,支持windows,solaris,
      下載地址:http://sourceforge.net/projects/xampp/files/
      啟動apache和mysql服務,如果apache不能成功啟動,最大原因是80端口被占用(),把占用端口的進程關掉即可.
    xampp默認安裝路徑為:C:\xampp
      解決方案:運行在cmd中運行 (安裝目錄)apache/bin/httpd.exe
      如我的路徑是“C:\xampp\apache\bin\httpd.exe”
      找到錯誤的具體原因(發現真的是端口被占用)
      “(OS 10048)通常每個套接字地址(協議/網絡地址/端口)只允許使用一次。  : AH00072: mak
      e_sock: could not bind to address 0.0.0.0:80
      AH00451: no listening sockets available, shutting down
      AH00015: Unable to open logs”
      轉自網絡
      XAMPP修改Apache端口 無法重啟服務
      由于先前裝了PHPNOW,之后又裝了XAMPP,XAMPP的apache服務就啟動不了,改了XAMPP的apache的端口號后,服務還是無法啟動;
      解決方法:由于apache中httpd.conf文件加載了SSL,而之前已有SSL,所以XAMPP要修改apache與SSL才可使用,或在httpd.conf文件中將SSL的加載用#號注釋掉,操作如下:
      打開apache配置文件,如D:\xampp\apache\conf\httpd.conf:
      修改“Listen 80”為“Listen 8080”;
      修改“ServerName localhost:80”為“ServerName localhost:8080”;
      打開SSL加載文件,如D:\xampp\apache\conf\extra\httpd-ssl.conf
      將所有443端口改為4433端口 或 直接在Apache配置文件httpd.conf中,去掉或注釋“Include "conf/extra/httpd-ssl.conf"”
      最后啟動mYSQL發現啟動不了,原因是我已經安裝了dedeCMS,其中也使用了XAMPP,所以果斷把安裝目錄刪除了,重裝,發現OK了,哈哈
      
      表示已經安裝成功,點擊界面上排右側可切換多種語言,這里選擇“中文”,將界面語言設置為中文。
      選擇左邊的“安全”選項
      
      紅字是不安全的,所以要去掉紅字。
      MySQL安全控制臺&XAMPP目錄保護
      瀏覽器中輸入http://localhost/security/xamppsecurity.php ,敲回車后出現如下圖:
      
      為mysql root設置密碼“111111”,輸入自己的密碼(這里需要自己設置密碼);PhpMyAdmin 認證選擇http,然后點擊【改變密碼】,密碼設置成功。
      設置Xampp目錄保護,輸入用戶名和密碼,點擊【保護XAMPP文件夾】后,提示XAMPP目錄保護設置成功。
      一定要記住密碼哦,每次配置的時候都需要輸入用戶名和密碼的。
      下面用PHPmyadimin配置mysql,在瀏覽器中輸入http://localhost/phpmyadmin,敲回車后如下圖
      
      下面用PHPmyadimin配置mysql,在瀏覽器中輸入http://localhost/phpmyadmin,敲回車后如下圖
      剛才設置的密碼在這里要用到了,用戶名輸入root,密碼輸入剛才自己設置的密碼。就可以進入數據庫了。
      如果重新登錄phpmyadmin,發現無法連接,需要在PHPmyadmin下配置config.inc.php文件,該文件位于
      C:\xampp\phpMyAdmin中,找到config.inc.php文件,打開編輯,配置如下:
      cfg[′Servers′][i]['auth_type']     = 'http';
      cfg[′Servers′][i]['user'] = 'root';
      cfg[′Servers′][i]['password'] = '123456';
      pwd那行,是根據自己情況設置的。保存一下就可以了。
      設置PHP運行于安裝模式
      這里設置和XAMPP 1.7的版本不同,1.8的版本中設置:
      在安裝好的XAMPP界面點擊Apache后側的Config會彈出一個下拉框,這里選擇打開
      PHP(php.ini),文檔打開后,查找safe_mode字段設置為ON保存退出。
      然后通過http://localhost/security/index.php檢查其狀態。
      bugfree3.0.4下載、安裝和配置:
      3.1 下載地址:
      3.2 安裝步驟:
      3.2.1 解壓后拷貝bugfree
      3.0.4至xampp安裝目錄的htdocs文件夾的根目錄下,例如D: \xampp\htdocs\,命名為bugfree3;
      3.2.2 瀏覽器中輸入http://localhost/bugfree3/install/,所有環境都檢查ok后 【繼續】按鈕變為可點擊狀態;
    上圖錯誤解決方法:xampp安裝目錄的htdocs文件夾的根目錄下新建BugFile文件夾。 修改后,點擊【繼續】至下圖
      解決:將上圖的數據庫用戶名改為root即可
      完成安裝,進入BugFree,初始用戶名: root  初始密碼:111111
      
      安裝成功了:
      

    posted @ 2014-09-17 09:42 順其自然EVO 閱讀(8393) | 評論 (1)編輯 收藏

    以用戶為中心的設計---可用性測試

      可用性測試是指,讓一群有代表性的用戶嘗試對產品進行典型造作,同時觀察員和開發人員在一旁觀察,聆聽,做記錄。
      每個產品設計者都希望自己的產品可用性非常的棒,非常的適合用戶使用習慣,減少用戶學習成本,并且具備更多人性化的功能。這也是每個互聯網公司所追求的,那么為了能在上線前,先評估產品的使用情況,我們會有一個用戶研究部門組織人員進行所謂的可用性測試。
      可用性測試有幾點我們需要明白:
      1.用戶是誰,找幾個用戶
      2.如何設計任務
      3.如何進行測試
      4.如何分析找到可用性問題
      1.用戶是誰,如何找用戶
      在我們進行可用性測試時,我們應該是找那些用戶,幾個用戶,一般來說多找“輕用戶”和“有潛在需求的人”;如果我們資金不足的情況下,可請5名參與測試人員和5名陪同測試人員,(也不是說人員越來約好,5個人可以把產品問題的80%找到),1個主持人。裝上必要的屏幕錄像軟件,即時的記錄用戶的操作軌跡。
      2.如何設計任務
      如果你實在不知道該測試那些,那么請您把產品的功能,按順序排列到表格,找出產品核心功能,再找出核心功能5個最重要的模塊,或者按照核心功能設計5個任務,任務不宜過多,如果多了測試人員煩躁,陪同人員也沒不耐煩。
      3.如何進行測試
      不要聽用戶說,要看他操作,說的不必做的來得實在。人往往是說一套做一套的。如果用戶操作出錯,先不用提醒,看用戶是否自行解決,陪同人員同時記錄問題,但不要急于討論問題的解決方案。馬上想到的方案或者用戶提出的方案都不一定是最好的。這個工作可以留待可以安靜思考或者大家討論時進行。
      4.如何分析找到可用性問題
      召集所有陪同人員,將所以記錄的問題匯總,然后找出可以馬上改進的問題,先把這些問題處理,接下來把大的東西再仔細的通過錄像,筆記進行仔細的考慮,后續與產品,交互等一起進行改進。

    posted @ 2014-09-17 09:40 順其自然EVO 閱讀(213) | 評論 (0)編輯 收藏

    關于UNIX功能測試宏

     UNIX的功能測試宏,在頭文件中定義了很多POSIX.1和XPG3的符號。但是除了POSIX.1和XPG3定義外,大多數實現在這些頭文件中也加上了他們自己的定義。如果在編譯一個程序時,希望它只是用POSIX定義而不使用任何實現定義的限制,那么就需要定義常數_POSIX_SOURCE,所有POSIX.1頭文件中都是用此常數。當該常數定義時,就能排除任何實現專有的定義。
      常數_POSIX_SOURCE及對應的常數_XOPEN_SOURCE被稱為功能性測試宏(feature test macro)。所有功能測試宏都以下劃線開始。要使用他們時,通常在cc命令行中以下列方式定義:
      cc -D_POSIX_SOURCE file.c
      這使得在C程序包括任何頭文件之前,定義了功能測試宏。如果我們僅想用POSIX.1定義,那么也可以將源文件的第一行設置為:
      #define _POSIX_SOURCE 1
      另一個功能測試宏是:__STDC__,它由符合ANSI C標準的編譯程序自動定義。這樣就允許我們編寫ANSI C編譯程序和非ANSI C編譯程序都能編譯的程序。例如,一個頭文件可能會是:
    void *myfunc(const char*, int);
    #else
    void *myfunc();
    #endif
    #ifdef __STDC__
    void *myfunc(const char*, int);
    #else
    void *myfunc();
    #endif
      這樣就能發揮ANSI C原型功能的長處,要注意在開始和結束的兩個連續的下劃線常常打印成一個長下劃線。

    posted @ 2014-09-17 09:38 順其自然EVO 閱讀(214) | 評論 (0)編輯 收藏

    測試用例在Scrum中有一席之地嗎?

     在Scrum中,需求通常以用戶故事表達。那么在Scrum中可以使用用例嗎?如果可以的話,什么情況下我們應該使用用例呢?
      Scott Kendrick問到:
      用例在Scrum中有一席之地嗎?我的直覺是,如果正確編寫了用戶故事,那就足以驅動討論和協作了,同時也足以用來制定測試用例了。
      首先,Scrum要求我們使用用戶故事,而不要使用用例嗎?Roy Morien認為不是:
      Scrum沒有強制任何引發誘導和記錄需求的方法,除了推薦面對面的對話、日常的站立會議(當然如果你想坐下也可以)、sprint計劃會議、甚至是用戶故事分析,Scrum推薦的就只有協作活動和透明性了。根據這些指導原則,我想這取決于你實際想做什么。
      鑒于此,在什么情況下你會想使用用戶故事呢?Charles Bradley建議:
      通常對于新的Scrum團隊,在他們轉向Scrum的頭幾個月,我建議他們就使用他們以前的需求搜集方法。學習Scrum時,不去學習一種全新的需求搜集方法會讓學習變得非常困難。
      同時Charles Bradley認為,“[……]Scrum的指導原則表明大部分Scrum團隊應該使用用戶故事,而對于那些要求‘任務/生命周期的行為要非常確定’的團隊,可以使用用例”。Adam Sroka不同意這種方法:
      傳統觀點認為,“關鍵”的應用程序需要更多文檔。我認為這是不對的。關鍵應用程序需要的是更多(以及更好)的驗證。要做到這一點,就需要詳盡的自動化測試,許多做“關鍵”應用程序的團隊都不那么做,這點我不能理解。
      但是,在純粹的功能范圍外,用例文檔可能會提供價值。Charles Bradley寫到:
      嗯,我曾經在航空領域工作過一段時間,盡管我沒有完備的知識來支持這份工作(比如,什么需求必須具備這個東西),在我們從事文檔工作的時候,讓我記憶猶新的是,編寫文檔的目的不是過程審計,而是找出飛機墜毀的起因和責任方(監管部門,訴訟保護)。因此,某些必要的文檔有助于(保護公司)那樣的工作,而且我認為,在某些時候用例可能會比用戶故事更加有助于證實你的案例(避免出錯)。
      像敏捷方法的所有方面一樣,對于用例給組織帶來的價值,應該要仔細檢查。你從付出的精力中究竟得到了什么?畢竟,就像Ron Jeffreis所說的,“我還沒有碰到過很多實際的人,真正善于編寫用例。”如果你承認你可能不擅長編寫用例,那么有什么事情是你一直在做的,能給你的組織帶來更多價值?

    posted @ 2014-09-17 09:32 順其自然EVO 閱讀(289) | 評論 (1)編輯 收藏

    Java中的JSON對象的使用

    申明:沒工作之前都沒聽過JSON,可能是自己太菜了。可能在前臺AJAX接觸到JSON,這幾天要求在純java的編程中,返回JSON字符串形式。
      網上有兩種解析JSON對象的jar包:JSON-lib.jar和json.jar,這里主要介紹JSON-lib.jar。
      jar包地址如下:
      json-lib-2.4-jdk15.jar所需全部JAR包.rar
      一、JSON-lib.jar還依賴以下jar包:
      commons-lang.jar
      commons-beanutils.jar
      commons-collections.jar
      commons-logging.jar
      ezmorph.jar
      json-lib-2.2.2-jdk15.jar
      二、應用
      JSON也是以key-value形式存在的。key是字符串,value可以是基本類型、JSONArray、JSONObject.
      JSONArray:[],望文生義也知道,他是數組形式,又可要放多個JSON
      JSONObject:{}就放一個JSON。
      由于他們的他們可以嵌套形式就比較多。
      三、輸出JSON實例考慮到對[]、{}進行對比,區別重復的變量,對變量名進行了首字母大寫,顯得不規范了。
    import net.sf.json.JSONArray;
    import net.sf.json.JSONObject;
    public class JSONTest {
    public static void main(String[] args) {
    JSONObject container1 = new JSONObject();
    container1.put("ClassName", "高三一班");
    System.out.println(container1.toString());
    JSONArray className = new JSONArray();
    className.add("高三一班");
    container1.put("className", className);
    System.out.println(container1.toString());
    JSONObject classInfo = new JSONObject();
    classInfo.put("stuCount", 50);
    classInfo.put("leader", "rah");
    container1.put("classInfo", classInfo);
    System.out.println(container1);
    JSONObject ClassInfo = new JSONObject();
    JSONArray stuCount = new JSONArray();
    stuCount.add(50);
    JSONArray leader = new JSONArray();
    leader.add("rah");
    ClassInfo.put("stuCount", stuCount);
    ClassInfo.put("leader", leader);
    container1.put("ClassInfo", ClassInfo);
    System.out.println(container1);
    JSONArray students = new JSONArray();
    JSONObject studentOne = new JSONObject();
    studentOne.put("name", "張麻子");
    studentOne.put("sex", "男");
    studentOne.put("age", 12);
    studentOne.put("hobby", "java develop");
    JSONObject studentTwo = new JSONObject();
    studentTwo.put("name", "王瘸子");
    studentTwo.put("sex", "男");
    studentTwo.put("age", 13);
    studentTwo.put("hobby", "C/C++ develop");
    students.add(studentOne);
    students.add(studentTwo);
    container1.put("students", students);
    System.out.println(container1);
    JSONArray Students = new JSONArray();
    JSONObject StudnetOne = new JSONObject();
    JSONArray name1 = new JSONArray();
    name1.add("張麻子");
    JSONArray sex1 = new JSONArray();
    sex1.add("男");
    JSONArray age1= new JSONArray();
    age1.add("12");
    JSONArray hobby1 = new JSONArray();
    hobby1.add("java develop");
    StudnetOne.put("name", name1);
    StudnetOne.put("sex", sex1);
    StudnetOne.put("age", age1);
    StudnetOne.put("hobby", hobby1);
    JSONObject StudnetTwo = new JSONObject();
    JSONArray name2 = new JSONArray();
    name2.add("王瘸子");
    JSONArray sex2 = new JSONArray();
    sex2.add("男");
    JSONArray age2= new JSONArray();
    age2.add("13");
    JSONArray hobby2 = new JSONArray();
    hobby2.add("C/C++ develop");
    StudnetTwo.put("name", name2);
    StudnetTwo.put("sex", sex2);
    StudnetTwo.put("age", age2);
    StudnetTwo.put("hobby", hobby2);
    Students.add(StudnetOne);
    Students.add(StudnetTwo);
    container1.put("Students", Students);
    System.out.println(container1);
    JSONArray teachers = new JSONArray();
    teachers.add(0,"王老師");
    teachers.add(1,"李老師 ");
    container1.put("teachers", teachers);
    System.out.println(container1);
    JSONArray Teachers = new JSONArray();
    JSONObject teacher1 = new JSONObject();
    teacher1.put("name", "小梅");
    teacher1.put("introduce","他是一個好老師");
    JSONObject teacher2 = new JSONObject();
    teacher2.put("name", "小李");
    teacher2.put("introduce","他是一個合格的老師");
    Teachers.add(0,teacher1);
    Teachers.add(1,teacher2);
    container1.put("Teachers", Teachers);
    System.out.println(container1);
    }
    }
    運行結果:
    {"ClassName":"高三一班"}
    {"ClassName":"高三一班","className":["高三一班"]}
    {"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"}}
    {"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]}}
    {"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"張麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}]}
    {"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"張麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}],"Students":[{"name":["張麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}]}
    {"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"張麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}],"Students":[{"name":["張麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}],"teachers":["王老師","李老師 "]}
    {"ClassName":"高三一班","className":["高三一班"],"classInfo":{"stuCount":50,"leader":"rah"},"ClassInfo":{"stuCount":[50],"leader":["rah"]},"students":[{"name":"張麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}],"Students":[{"name":["張麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}],"teachers":["王老師","李老師 "],"Teachers":[{"name":"小梅","introduce":"他是一個好老師"},{"name":"小李","introduce":"他是一個合格的老師"}]}
      四、遍歷JSON實例
      以上面的輸出的JSON字符串進行按順序給它遍歷
      String ClassName1 = (String) container1.get("ClassName");
      System.out.println("ClassName data is: " + ClassName1);
      JSONArray className1 = container1.getJSONArray("className");
      System.out.println("className data is: " + className1);
      JSONObject classInfo1 = container1.getJSONObject("classInfo");
      System.out.println("classInfo data is: " + classInfo1);
      JSONObject ClassInfo1 = container1.getJSONObject("ClassInfo");
      System.out.println("ClassInfo data is: " + ClassInfo1);
      JSONArray students1 = container1.getJSONArray("students");
      System.out.println("students data is: " + students1);
      JSONArray Students1 = container1.getJSONArray("Students");
      System.out.println("Students data is: " + Students1);
      JSONArray teachers1 = container1.getJSONArray("teachers");
      for(int i=0; i < teachers1.size(); i++){
      System.out.println("teahcer " + i + " is: "+ teachers1.get(i));
      }
      JSONArray Teachers1 = container1.getJSONArray("Teachers");
      for(int i=0; i < Teachers1.size(); i++){
      System.out.println("Teachers " + i + " is: "+ Teachers1.get(i));
      }
      遍歷結果:
      ClassName data is: 高三一班
      className data is: ["高三一班"]
      classInfo data is: {"stuCount":50,"leader":"rah"}
      ClassInfo data is: {"stuCount":[50],"leader":["rah"]}
      students data is: [{"name":"張麻子","sex":"男","age":12,"hobby":"java develop"},{"name":"王瘸子","sex":"男","age":13,"hobby":"C/C++ develop"}]
      Students data is: [{"name":["張麻子"],"sex":["男"],"age":["12"],"hobby":["java develop"]},{"name":["王瘸子"],"sex":["男"],"age":["13"],"hobby":["C/C++ develop"]}]
      teahcer 0 is: 王老師
      teahcer 1 is: 李老師
      Teachers 0 is: {"name":"小梅","introduce":"他是一個好老師"}
      Teachers 1 is: {"name":"小李","introduce":"他是一個合格的老師"}
      上面包括了大部份的JSON的嵌套形式,可能有忽略的也可以參考上面的內容。

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

    IOS開發之顯示微博表情

     在上一篇博客中山寨了一下新浪微博,在之后的博客中會對上一篇代碼進行優化和重用,上一篇的微博請求的文字中有一些表情沒做處理,比如帶有表情的文字是這樣的“我要[大笑],[得意]”。顯示的就是請求的字符串,那么我們如何把文字在本地轉換成表情呢?下面將要說一下顯示表情的解決方案。
      要用到的知識:IOS開發中的資源文件.plist, 可變的屬性字符串,TextView和正則表達式的使用。
      解決的整體思路:把源字符串同過正則匹配獲取到每個表情的range, 再通過range獲取元字符串中的表情字符串,如[哈哈], 在把[哈哈] 和我們.plist中item下的chs字段匹配,然后獲取對應的圖片名,獲取圖片后把圖片轉換成可變字符串的附件,然后做一個替換即可。先這么大致一說,下面會詳細的講解一下。
      1.要想在我們手機上顯示網絡請求的表情,首先我們本地得有相應的資源文件,在.plist文件中又我們想要的東西,其中存儲的東西如下所示,整個root是一個數組,數組中的item是一個字典,字典中存放的時文字到圖片名的一個映射,當然啦,圖片名和我們本地資源的圖片名相同。截圖如下
      2.如何從.plist文件中獲取數據呢?先通過bundle獲取資源文件的路徑,在通過文件路徑創建數組,數組中存儲的數據就是文件中的內容代碼如下:
      //加載plist文件中的數據
      NSBundle *bundle = [NSBundle mainBundle];
      //尋找資源的路徑
      NSString *path = [bundle pathForResource:@"emoticons" ofType:@"plist"];
      //獲取plist中的數據
      NSArray *face = [[NSArray alloc] initWithContentsOfFile:path];
      3.生成我們的測試字符串,最后一個不是任何表情,不做替換。
      //我們要顯示的字符串(模擬網路請求的字符串格式)
      NSString *str = @"我[圍觀]你[威武]你[嘻嘻]我[愛你]你[兔子]我[酷]你[帥]我[思考]你[錢][123456]";
      4.把上面的str轉換為可變的屬性字符串,因為我們要用可變的屬性字符串在TextView上顯示我們的表情圖片,轉換代碼如下:
      //創建一個可變的屬性字符串
      NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:str];
      5.進行正則匹配,獲取每個表情在字符串中的范圍,下面的正則表達式會匹配[/*],所以[123567]也會被匹配上,下面我們會做相應的處理
      //正則匹配要替換的文字的范圍
      //正則表達式
      NSString * pattern = @"\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]";
      NSError *error = nil;
      NSRegularExpression * re = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];
      if (!re) {
      NSLog(@"%@", [error localizedDescription]);
      }
      //通過正則表達式來匹配字符串
      NSArray *resultArray = [re matchesInString:str options:0 range:NSMakeRange(0, str.length)]; 6.數據準備工作完成,下面開始遍歷資源文件找到文字對應的圖片,找到后把圖片名存入字典中,圖片在源字符串中的位置也要存入到字典中,最后把字典存入可變數組中。代碼如下:
    1     //用來存放字典,字典中存儲的是圖片和圖片對應的位置
    2     NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count];
    3
    4     //根據匹配范圍來用圖片進行相應的替換
    5     for(NSTextCheckingResult *match in resultArray) {
    6         //獲取數組元素中得到range
    7         NSRange range = [match range];
    8
    9         //獲取原字符串中對應的值
    10         NSString *subStr = [str substringWithRange:range];
    11
    12         for (int i = 0; i < face.count; i ++)
    13         {
    14             if ([face[i][@"chs"] isEqualToString:subStr])
    15             {
    16
    17                 //face[i][@"gif"]就是我們要加載的圖片
    18                 //新建文字附件來存放我們的圖片
    19                 NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
    20
    21                 //給附件添加圖片
    22                 textAttachment.image = [UIImage imageNamed:face[i][@"png"]];
    23
    24                 //把附件轉換成可變字符串,用于替換掉源字符串中的表情文字
    25                 NSAttributedString *imageStr = [NSAttributedString attributedStringWithAttachment:textAttachment];
    26
    27                 //把圖片和圖片對應的位置存入字典中
    28                 NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2];
    29                 [imageDic setObject:imageStr forKey:@"image"];
    30                 [imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"];
    31
    32                 //把字典存入數組中
    33                 [imageArray addObject:imageDic];
    34
    35             }
    36         }
    37     }
      7.轉換完成,我們需要對attributeString進行替換,替換的時候要從后往前替換,弱從前往后替換,會造成range和圖片要放的位置不匹配的問題。替換代碼如下:
    1     //從后往前替換
    2     for (int i = imageArray.count -1; i >= 0; i--)
    3     {
    4         NSRange range;
    5         [imageArray[i][@"range"] getValue:&range];
    6         //進行替換
    7         [attributeString replaceCharactersInRange:range withAttributedString:imageArray[i][@"image"]];
    8
    9     }
      8.把替換好的可變屬性字符串賦給TextView
      1     //把替換后的值賦給我們的TextView
      2     self.myTextView.attributedText = attributeString;
      9.替換前后效果如下:

    posted @ 2014-09-16 09:52 順其自然EVO 閱讀(1735) | 評論 (1)編輯 收藏

    VS2013單元測試(使用VS2013自帶的單元測試)

     1、打開VS3013,隨便建一個解決方案,比如叫:LearnUnitTest,建一個類庫項目LearnUnitTest_Bank,該項目中添加一個BankAccount類,這個類及類中的方法就是我們要測試的對象。
      2、給LearnUnitTest添加一個測試項目:在解決方案名稱上右鍵=》添加=》新建項目=》VisualC#=》測試=》單元測試項目,項目名稱叫LearnUnitTest_BankTest,將LearnUnitTest_Bank添加為LearnUnitTest_BankTest的引用項目,將測試項目LearnUnitTest_BankTest里默認生成的類重命名為BankAccountTest。
      對于BankAccountTest類,類上有注解TestClass,方法上有注解TestMethod。可以在這類文件里添加其他類和方法,供測試方法使用。
      首個測試:
      3、現在我們測試BankAccount類的Debit方法,我們預先確定此次測試要檢查如下方面:
      a、如果信用余額(credit amount)比賬戶余額大,該方法就拋異常ArgumentOutOfRangeException
      b、如果信用余額小于0也拋異常
      c、如果a和b都滿足,該方法會從賬戶余額里減去amount(函數參數)
      注意:由a、b、c可以看郵BankAccount類中的Debit方法最后一行應該是-=,而不是+=——當然了,這個是故意留下的bug,而不是微軟的失誤,就等著在這次測試中把它測出來,然后修正掉。
      在測試類里添加如下方法測試Debit方法:
    // unit test code
    [TestMethod]
    public void Debit_WithValidAmount_UpdatesBalance()
    {
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = 4.55;
    double expected = 7.44;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
    // act
    account.Debit(debitAmount);
    // assert
    double actual = account.Balance;
    Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly");
    }
      測試方法的要求:
      必須要有TestMethod注解,返回類型為void,不能有參數。
      經過測試,我們發現了bug,把+=改為-=即可。
      使用單元測試改善代碼:
      依然是測試Debit,本次測試想完成以下意圖:
      a、如果credit amount(指的應該就是debit amount)比balance大,方法就拋ArgumentOutOfRangeException
      b、如果credit amount比0小,也拋ArgumentOutOfRangeException異常
      (1)創建測試方法
      首次嘗試創建一個測試方法來處理上述問題:
      代碼:
    //unit test method
    [TestMethod]
    [ExpectedException(typeof(ArgumentOutOfRangeException))]
    public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()
    {
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = -100.00;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);
    // act
    account.Debit(debitAmount);
    // assert is handled by ExpectedException
    }
      注意這個方法:Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange,意思是:當debit amount小于0時,本次測試應該會導致被測試的方法拋出ArgumentOutOfRange異常,否則本次測試就失敗了,沒有達到期望,需要修改Debit代碼以達成本次測試期望——正所謂TDD開發。
      我們使用了ExpectedExceptionAttribute特性來斷言期望的異常應當被拋出。除非方法拋出ArgumentOutOfRangeException異常,否則該特性就會導致測試失敗(要注意本次測試的意圖)。用正的和負的debitAmount運行這個測試,然后臨時把被測試的方法(Debit方法)修改一下:當demit amount小于0時拋出一個ApplicatinException。搗騰完這些,發現本次測試基本沒什么問題。
      為了測試debit amount 大于balance的情形,我們做下面幾個操作:
      a、創建一個新的測試方法名叫    Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
      b、從上一個測試方法
      Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange
      復制方法體到本測試方法
      c、把debitAmount設置為一個比balance大的值
      (2)運行測試方法
      用不同的debitAmount值運行Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
      和 Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange
      然后運行三個測試,這樣我們最開始設定的三個cases都被覆蓋了。
     (3)繼續分析
      后面兩個測試方法Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
      和Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange
      有些問題:兩個測試運行的時候根據拋出的異常,你不知道是誰拋出的,靠ExpectedException特性做不到這件事。
      可以這樣修改:
      在類里定義兩個常量:
    // class under test
    public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance";
    public const string DebitAmountLessThanZeroMessage = "Debit amount less than zero";
    // method under test
    // ...
    if (amount > m_balance)
    {
    throw new ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage);
    }
    if (amount < 0)
    {
    throw new ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage);
    }
    // ...
      (4)重構測試方法
      首先,移除ExpectedException特性。取而代之的處理是:我們捕獲異常,來核實是在哪種條件下拋出的。
      修改一下Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
      方法:
    [TestMethod]
    public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
    {
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = 20.0;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\
    // act
    try
    {
    account.Debit(debitAmount);
    }
    catch (ArgumentOutOfRangeException e)
    {
    // assert
    StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
    }
    }
      (5)再次測試,再次重寫,再次分析
      當我們用不的參數再次運行測試方法Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
      的時候,會遇到下面一些問題:
      1、如果我們使用一個比balance大的debitAmount運行,產生的測試結果是所期望的。
      2、如果使用了一個debitAmount運行,使得assert 斷言失敗了(比如在Debit方法的某一行返回了一個非期望的異常),也沒什么問題,在本測試的情理之中。
      3、如果debitAmount是有效的(比0大比balance小)會發生什么呢?沒有異常拋出,斷言也不會失敗,測試方法通過了。——這不是我們想要的,注意我們此次的測試初衷:要么斷言成功,要么斷言失敗,如果壓根進入不了斷言代碼,只能說明測試方法寫的問題!
      為了解決這個問題,我們在測試方法的最后一行加入一個Fail斷言,來處理沒有異常發生的情況:沒有異常發生,就說明此次測試沒有達到期望!
      但是修改好再次運行,會發現如果所期望的異常被捕獲了,測試總會失敗。為了解決這個問題,我們在StringAssert之前加一個return。
      最終我們的Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
      方法如下:
    [TestMethod]
    public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
    {
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = 20.0;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\
    // act
    try
    {
    account.Debit(debitAmount);
    }
    catch (ArgumentOutOfRangeException e)
    {
    // assert
    StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
    return;
    }
    Assert.Fail("No exception was thrown.")
    }
      最終我們讓測試代碼變得更加強健,但更重要的是,在這個過程中,我也們也改善了被測試的代碼——這才是測試的最終目的。

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

    關于UNIX功能測試宏

    UNIX的功能測試宏,在頭文件中定義了很多POSIX.1和XPG3的符號。但是除了POSIX.1和XPG3定義外,大多數實現在這些頭文件中也加上了他們自己的定義。如果在編譯一個程序時,希望它只是用POSIX定義而不使用任何實現定義的限制,那么就需要定義常數_POSIX_SOURCE,所有POSIX.1頭文件中都是用此常數。當該常數定義時,就能排除任何實現專有的定義。
      常數_POSIX_SOURCE及對應的常數_XOPEN_SOURCE被稱為功能性測試宏(feature test macro)。所有功能測試宏都以下劃線開始。要使用他們時,通常在cc命令行中以下列方式定義:
      cc -D_POSIX_SOURCE file.c
      這使得在C程序包括任何頭文件之前,定義了功能測試宏。如果我們僅想用POSIX.1定義,那么也可以將源文件的第一行設置為:
      #define _POSIX_SOURCE 1
      另一個功能測試宏是:__STDC__,它由符合ANSI C標準的編譯程序自動定義。這樣就允許我們編寫ANSI C編譯程序和非ANSI C編譯程序都能編譯的程序。例如,一個頭文件可能會是:
    void *myfunc(const char*, int);
    #else
    void *myfunc();
    #endif
    #ifdef __STDC__
    void *myfunc(const char*, int);
    #else
    void *myfunc();
    #endif
      這樣就能發揮ANSI C原型功能的長處,要注意在開始和結束的兩個連續的下劃線常常打印成一個長下劃線。

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

    數據庫中的事物處理

     數據庫
      數據庫的更新通常都是由客觀世界的所發生的事件引起的。為保證數據庫內容的一致,就要將數據庫的一組操作作為一個整體來進行,要么全部成功完成,要么全部失敗退出。如果由于故障或其它原因而使一組操作中有一些完成,有一些未完成,則必然會使得數據庫中的數據出現不一致,從而使得數據庫的完整性受到破壞。因此,更新操作序列必須作為一個整體在DBMS執行時出現,即“要么全做,要么全不做”。SQL提供了事務處理的機制,來幫助DBMS實現上述的功能。
      事務處理
      事務處理(TRANSACTION)的每個語句是由一個或多個SQL語句序列結合在一起所形成的一個邏輯處理單元。事務處理中句都是完成整個任務的一部分工作,所有的語句組織在一起能夠完成某一特定的任務。DBMS在對事務處理中的語句進行處理時,是按照下面的約定來進行的,這就是“事務處理中的所有語句被作為一個原子工作單位,所有的語句既可成功地被執行,也可以沒有任何一個語句被執行”。DBMS負責完成這種約定,即使在事務處理中應用程序異常退出,或者是硬件出現故障等各種意外情況下,也是如此。在任何意外情況下,DBMS都負責確保在系統恢復正常后,數據庫內容決不會出現“部分事務處理中的語句被執行完”的情況。
      sql語言
      sql語言為事務處理提供了兩個重要的語句,它們是COMMIT和ROLLBACK語句。它們的使用格式是:
      COMMIT WORK
      ROLLBACK WORK
      COMMIT語句用于告訴DMBS,事務處理中的語句被成功執行完成了。被成功執行完成后,數據庫內容將是完整的。而ROLLBACK語句則是用于告訴DBMS,事務處理中的語句不能被成功執行。這時候,DBMS將恢復本次事務處理期間對數據庫所進行的修改,使之恢復到本次事務處理之前的狀態。
      事務處理:
    QSqlDatabase::database().transaction();
    QSqlQuery query;
    query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
    if (query.next())
    {
    int employeeId = query.value(0).toInt();
    query.exec("INSERT INTO project (id, name, ownerid) "
    "VALUES (201, 'Manhattan Project', "
    + QString::number(employeeId) + ")");
    }
    QSqlDatabase::database().commit();
      如果數據庫引擎支持事務處理,則函數QSqlDriver::hasFeature(QSqlDriver::Transactions)將返回 真。
      可以通過調用QSqlDatabase::transaction()來初始化一個事務處理。之后執行你想在該事務處理的工作。
      完了再執行QSqlDatabase::commit()來提交事務處理或QSqlDatabase::rollback()取消事務處理。

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

    僅列出標題
    共394頁: First 上一頁 46 47 48 49 50 51 52 53 54 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 四虎影视大全免费入口| 亚洲美女在线国产| 美女视频黄a视频全免费网站一区 美女视频黄a视频全免费网站色 | 久久亚洲中文字幕精品有坂深雪 | 大学生一级特黄的免费大片视频| 国产成人久久精品亚洲小说| 久久精品国产精品亚洲蜜月| 国产91精品一区二区麻豆亚洲 | 免费高清A级毛片在线播放| 亚洲av无码潮喷在线观看| 女人被男人桶得好爽免费视频| 国产高清视频免费在线观看| 亚洲国产精品成人综合久久久| 又粗又硬又大又爽免费视频播放| 免费精品无码AV片在线观看| 亚洲.国产.欧美一区二区三区| 亚洲av片劲爆在线观看| 午夜成年女人毛片免费观看| 国产色爽免费无码视频| 成人婷婷网色偷偷亚洲男人的天堂 | 久久大香香蕉国产免费网站| 精品国产亚洲AV麻豆| 亚洲综合激情另类小说区| 亚洲国产中文v高清在线观看| 国产妇乱子伦视频免费| 久久久受www免费人成| 亚洲欧美不卡高清在线| 亚洲黄色中文字幕| 亚洲最大AV网站在线观看| 四色在线精品免费观看| 1000部啪啪未满十八勿入免费| 精品国产免费一区二区三区| 亚洲精品动漫免费二区| 日本一区免费电影| 69xx免费观看视频| 日韩电影免费观看| 黄床大片免费30分钟国产精品| 色欲色欲天天天www亚洲伊| 亚洲一级毛片在线观| 色拍自拍亚洲综合图区| 亚洲情XO亚洲色XO无码|