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

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

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

    qileilove

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

    簡單十步讓你全面理解SQL

     很多程序員認為SQL是一頭難以馴服的野獸。它是為數(shù)不多的聲明性語言之一,也因為這樣,其展示了完全不同于其他的表現(xiàn)形式、命令式語言、 面向?qū)ο笳Z言甚至函數(shù)式編程語言(雖然有些人覺得SQL 還是有些類似功能)。
      我每天都寫SQL,我的開源軟件JOOQ中也包含SQL。因此我覺得有必要為還在為此苦苦掙扎的你呈現(xiàn)SQL的優(yōu)美!下面的教程面向于:
      已經(jīng)使用過但沒有完全理解SQL的讀者
      已經(jīng)差不多了解SQL但從未真正考慮過它的語法的讀者
      想要指導他人學習SQL的讀者
      本教程將重點介紹SELECT 語句。其他 DML 語句將在另一個教程中在做介紹。接下來就是…
      1、SQL是聲明性語言
      首先你需要思考的是,聲明性。你唯一需要做的只是聲明你想獲得結(jié)果的性質(zhì),而不需要考慮你的計算機怎么算出這些結(jié)果的。
      SELECT first_name, last_name FROM employees WHERE salary > 100000
      這很容易理解,你無須關(guān)心員工的身份記錄從哪來,你只需要知道誰有著不錯的薪水。
      從中我們學到了什么呢?
      那么如果它是這樣的簡單,會出現(xiàn)什么問題嗎?問題就是我們大多數(shù)人會直觀地認為這是命令式編程。如:“機器,做這,再做那,但在這之前,如果這和那都發(fā)生錯誤,那么會運行一個檢測”。這包括在變量中存儲臨時的編寫循環(huán)、迭代、調(diào)用函數(shù),等等結(jié)果。
      把那些都忘了吧,想想怎么去聲明,而不是怎么告訴機器去計算。
      2、SQL語法不是“有序的”
      常見的混亂源于一個簡單的事實,SQL語法元素并不會按照它們的執(zhí)行方式排序。語法順序如下:
    SELECT [DISTINCT]
    FROM
    WHERE
    GROUP BY
    HAVING
    UNION
    ORDER BY
      為簡單起見,并沒有列出所有SQL語句。這個語法順序與邏輯順序基本上不同,執(zhí)行順序如下:
    FROM
    WHERE
    GROUP BY
    HAVING
    SELECT
    DISTINCT
    UNION
    ORDER BY
      這有三點需要注意:
      1、第一句是FROM,而不是SELECT。首先是將數(shù)據(jù)從磁盤加載到內(nèi)存中,以便對這些數(shù)據(jù)進行操作。
      2、SELECT是在其他大多數(shù)語句后執(zhí)行,最重要的是,在FROM和GROUP BY之后。重要的是要理解當你覺得你可以從WHERE語句中引用你定義在SELECT語句當中的時候,。以下是不可行的:
      SELECT A.x + A.y AS z
      FROM A
      WHERE z = 10 -- z is not available here!
    如果你想重用z,您有兩種選擇。要么重復表達式:
      SELECT A.x + A.y AS z
      FROM A
      WHERE (A.x + A.y) = 10
      或者你使用派生表、公用表表達式或視圖來避免代碼重復。請參閱示例進一步的分析:
      3、在語法和邏輯順序里,UNION都是放在ORDER BY之前,很多人認為每個UNION子查詢都可以進行排序,但根據(jù)SQL標準和大多數(shù)的SQL方言,并不是真的可行。雖然一些方言允許子查詢或派生表排序,但卻不能保證這種順序能在UNION操作后保留。
      需要注意的是,并不是所有的數(shù)據(jù)庫都以相同的形式實現(xiàn),例如規(guī)則2并不完全適用于MySQL,PostgreSQL,和SQLite上
      從中我們學到了什么呢?
      要時刻記住SQL語句的語法順序和邏輯順序來避免常見的錯誤。如果你能明白這其中的區(qū)別,就能明確知道為什么有些可以執(zhí)行有些則不能。
      如果能設計一種在語法順序上實際又體現(xiàn)了邏輯順序的語言就更好了,因為它是在微軟的LINQ上實現(xiàn)的。
      3、SQL是關(guān)于數(shù)據(jù)表引用的
      因為語法順序和邏輯順序的差異,大多數(shù)初學者可能會誤認為SQL中列的值是第一重要的。其實并非如此,最重要的是數(shù)據(jù)表引用。
      該SQL標準定義了FROM語句,如下:
      <from clause> ::= FROM &lt;table reference&gt; [ { &lt;comma&gt; &lt;table reference&gt; }... ]
      ROM語句的"output"是所有表引用的結(jié)合程度組合表引用。讓我們慢慢地消化這些。
      FROM a, b
      上述產(chǎn)生一個a+b度的組合表引用,如果a有3列和b有5列,那么"輸出表"將有8(3+5)列。
      包含在這個組合表引用的記錄是交叉乘積/笛卡兒積的axb。換句話說,每一條a記錄都會與每一條b記錄相對應。如果a有3個記錄和b有5條記錄,然后上面的組合表引用將產(chǎn)生15條記錄(3×5)。
      在WHERE語句篩選后,GROUP BY語句中"output"是"fed"/"piped",它已轉(zhuǎn)成新的"output",我們會稍后再去處理。
      如果我們從關(guān)系代數(shù)/集合論的角度來看待這些東西,一個SQL表是一個關(guān)系或一組元素組合。每個SQL語句將改變一個或幾個關(guān)系,來產(chǎn)生新的關(guān)系。
      從中我們學到了什么呢?
      一直從數(shù)據(jù)表引用角度去思考,有助于理解數(shù)據(jù)怎樣通過你的sql語句流水作業(yè)的
      4、SQL數(shù)據(jù)表引用可以相當強大
      表引用是相當強大的東西。舉個簡單的例子,JOIN關(guān)鍵字其實不是SELECT語句的一部分,但卻是"special"表引用的一部分。連接表,在SQL標準中有定義(簡化的):
      <table reference> ::=
      <table name>
      | <derived table>
      | <joined table>
      如果我們又拿之前的例子來分析:
      FROM a, b
      a可以作為一個連接表,如:
      a1 JOIN a2 ON a1.id = a2.id
      這擴展到前一個表達式,我們會得到:
      FROM a1 JOIN a2 ON a1.id = a2.id, b
      雖然結(jié)合了數(shù)據(jù)表引用語法與連接表語法的逗號分隔表讓人很無語,但你肯定還會這樣做的。結(jié)果,結(jié)合數(shù)據(jù)表引用將有a1+a2+b度。
      派生表甚至比連接表更強大,我們接下來將會說到。
      從中我們學到了什么呢?
      要時時刻刻考慮表引用,重要的是這不僅讓你理解數(shù)據(jù)怎樣通過你的sql語句流水作業(yè)的,它還將幫助你了解復雜表引用是如何構(gòu)造的。
      而且,重要的是,了解JOIN是構(gòu)造連接表的關(guān)鍵字。不是的SELECT語句的一部分。某些數(shù)據(jù)庫允許JOIN在插入、更新、刪除中使用。
      5、應使用SQL JOIN的表,而不是以逗號分隔表
      前面,我們已經(jīng)看到這語句:
      FROM a, b
      高級SQL開發(fā)人員可能會告訴你,最好不要使用逗號分隔的列表,并且一直完整的表達你的JOINs。這將有助于改進你的SQL語句的可讀性從而防止錯誤出現(xiàn)。
      一個非常常見的錯誤是忘記某處連接謂詞。思考以下內(nèi)容:
      FROM a, b, c, d, e, f, g, h
      WHERE a.a1 = b.bx
      AND a.a2 = c.c1
      AND d.d1 = b.bc
      -- etc...
      使用join來查詢表的語法
      更安全,你可以把連接謂詞與連接表放一起,從而防止錯誤。
      更富于表現(xiàn)力,你可以區(qū)分外部連接,內(nèi)部連接,等等。??
      從中我們學到了什么呢?
      使用JOIN,并且永遠不在FROM語句中使用逗號分隔表引用。
      6、SQL的不同類型的連接操作
      連接操作基本上有五種
      EQUI JOIN
      SEMI JOIN
      ANTI JOIN
      CROSS JOIN
      DIVISION
      這些術(shù)語通常用于關(guān)系代數(shù)。對上述概念,如果他們存在,SQL會使用不同的術(shù)語。讓我們仔細看看:
      EQUI JOIN(同等連接)
      這是最常見的JOIN操作。它有兩個子操作:
      INNER JOIN(或者只是JOIN)
      OUTER JOIN(可以再次拆分為LEFT, RIGHT,FULL OUTER JOIN)
      例子是其中的區(qū)別最好的解釋:
    -- This table reference contains authors and their books.
    -- There is one record for each book and its author.
    -- authors without books are NOT included
    author JOIN book ON author.id = book.author_id
    -- This table reference contains authors and their books
    -- There is one record for each book and its author.
    -- ... OR there is an "empty" record for authors without books
    -- ("empty" meaning that all book columns are NULL)
    author LEFT OUTER JOIN book ON author.id = book.author_id
      SEMI JOIN(半連接)
      這種關(guān)系的概念在SQL中用兩種方式表達:使用IN謂詞或使用EXISTS謂語。"Semi"是指在拉丁語中的"half"。這種類型的連接用于連接只有"half"的表引用。再次考慮上述加入的作者和書。讓我們想象,我們想要作者/書的組合,但只是那些作者實際上也有書。然后我們可以這樣寫:
      -- Using IN
      FROM author
      WHERE author.id IN (SELECT book.author_id FROM book)
      -- Using EXISTS
      FROM author
      WHERE EXISTS (SELECT 1 FROM book WHERE book.author_id = author.id)
      雖然不能肯定你到底是更加喜歡IN還是EXISTS,而且也沒有規(guī)則說明,但可以這樣說:
      IN往往比EXISTS更具可讀性
      EXISTS往往比IN更富表現(xiàn)力(如它更容易表達復雜的半連接)
      一般情況下性能上沒有太大的差異,但,在某些數(shù)據(jù)庫可能會有巨大的性能差異。
      因為INNER JOIN有可能只產(chǎn)生有書的作者,因為很多初學者可能認為他們可以使用DISTINCT刪除重復項。他們認為他們可以表達一個像這樣的半聯(lián)接:
      -- Find only those authors who also have books
      SELECT DISTINCT first_name, last_name
      FROM author
      這是非常不好的做法,原因有二:
      它非常慢,因為該數(shù)據(jù)庫有很多數(shù)據(jù)加載到內(nèi)存中,只是要再刪除重復項。
      它不完全正確,即使在這個簡單的示例中它產(chǎn)生了正確的結(jié)果。但是,一旦你JOIN更多的表引用,,你將很難從你的結(jié)果中正確刪除重復項。
      更多的關(guān)于DISTINCT濫用的問題,可以訪問這里的博客。
      ANTI JOIN(反連接)
      這個關(guān)系的概念跟半連接剛好相反。您可以簡單地通過將 NOT 關(guān)鍵字添加到IN 或 EXISTS中生成它。在下例中,我們選擇那些沒有任何書籍的作者:
      -- Using IN
      FROM author
      WHERE author.id NOT IN (SELECT book.author_id FROM book)
      -- Using EXISTS
      FROM author
      WHERE NOT EXISTS (SELECT 1 FROM book WHERE book.author_id = author.id)
      同樣的規(guī)則對性能、可讀性、表現(xiàn)力都適用。然而,當使用NOT IN時對NULLs會有一個小警告,這個問題有點超出本教程范圍。
      CROSS JOIN(交叉連接)
      結(jié)合第一個表中的內(nèi)容和第二個表中的內(nèi)容,引用兩個join表交叉生成一個新的東西。我們之前已經(jīng)看到,這可以在FROM語句中通過逗號分隔表引用來實現(xiàn)。在你確實需要的情況下,可以在SQL語句中明確地寫一個CROSS JOIN。
      -- Combine every author with every book
      author CROSS JOIN book
      DIVISION(除法)
      關(guān)系分割就是一只真正的由自己親自喂養(yǎng)的野獸。簡而言之,如果JOIN是乘法,那么除法就是JOIN的反義詞。在SQL中,除法關(guān)系難以表達清楚。由于這是一個初學者的教程,解釋這個問題超出了我們的教程范圍。當然如果你求知欲爆棚,那么就看這里,這里還有這里。
      從中我們學到了什么呢?
      讓我們把前面講到的內(nèi)容再次牢記于心。SQL是表引用。連接表是相當復雜的表引用。但關(guān)系表述和SQL表述還是有點區(qū)別的,并不是所有的關(guān)系連接操作都是正規(guī)的SQL連接操作。對關(guān)系理論有一點實踐與認識,你就可以選擇JOIN正確的關(guān)系類型并能將其轉(zhuǎn)化為正確的SQL。

     7、SQL的派生表就像表的變量
      前文,我們已經(jīng)了解到SQL是一種聲明性語言,因此不會有變量。(雖然在一些SQL語句中可能會存在)但你可以寫這樣的變量。那些野獸一般的表被稱為派生表。
      派生表只不過是包含在括號里的子查詢。
      -- A derived table
      FROM (SELECT * FROM author)
      需要注意的是,一些SQL方言要求派生表有一個關(guān)聯(lián)的名字(也被稱為別名)。
      -- A derived table with an alias
      FROM (SELECT * FROM author) a
      當你想規(guī)避由SQL子句邏輯排序造成的問題時,你會發(fā)現(xiàn)派生表可以用帥呆了來形容。例如,如果你想在SELECT和WHERE子句中重用一個列表達式,只寫(Oracle方言):
      -- Get authors' first and last names, and their age in days
      SELECT first_name, last_name, age
      FROM (
      SELECT first_name, last_name, current_date - date_of_birth age
      FROM author
      )
      -- If the age is greater than 10000 days
      WHERE age > 10000
      注意,一些數(shù)據(jù)庫和SQL:1999標準里已將派生表帶到下一級別,,引入公共表表達式。這將允許你在單一的SQL SELECT中重復使用相同的派生表。上面的查詢將轉(zhuǎn)化為類似這樣的:
      WITH a AS (
      SELECT first_name, last_name, current_date - date_of_birth age
      FROM author
      )
      SELECT *
      FROM a
      WHERE age > 10000
      很明顯,對廣泛重用的常見SQL子查詢,你也可以灌輸具體"a"到一個獨立視圖中。想要了解更多就看這里。
      從中我們學到了什么呢?
      再溫習一遍,SQL主要是關(guān)于表引用,而不是列。好好利用這些表引用。不要害怕寫派生表或其他復雜的表引用。
      8、SQL GROUP BY轉(zhuǎn)換之前的表引用
      讓我們重新考慮我們之前的FROM語句:
      FROM a, b
      現(xiàn)在,讓我們來應用一個GROUP BY語句到上述組合表引用
      GROUP BY A.x, A.y, B.z
      這會產(chǎn)生一個只有其余三個列(!)的新的表引用。讓我們再消化一遍。如果你用了GROUP BY,那么你在所有后續(xù)邏輯條款-包括選擇中減少可用列的數(shù)量。這就是為什么你只可以從SELECT語句中的GROUP BY語句引用列語法的原因。
      請注意,其他列仍然可能可作為聚合函數(shù)的參數(shù):
      SELECT A.x, A.y, SUM(A.z)
      FROM A
      GROUP BY A.x, A.y
      值得注意并很不幸的是,MySQL不遵守這一標準,只會造成混亂。不要陷入MySQL的把戲。GROUP BY轉(zhuǎn)換表引用,因此你可以只引用列也引用GROUPBY語句。
      從中我們學到了什么呢?
      GROUP BY,在表引用上操作,將它們轉(zhuǎn)換成一個新表。
      9、SQL SELECT在關(guān)系代數(shù)中被稱為投影
      當它在關(guān)系代數(shù)中使用時,我個人比較喜歡用"投影"一詞中。一旦你生成你的表引用,過濾,轉(zhuǎn)換它,你可以一步將它投影到另一個表中。SELECT語句就像一個投影機。表函數(shù)利用行值表達式將之前構(gòu)造的表引用的每個記錄轉(zhuǎn)化為最終結(jié)果。
      在SELECT語句中,你終于可以在列上操作,創(chuàng)建復雜的列表達式作為記錄/行的一部分。
      有很多關(guān)于可用的表達式,函數(shù)性質(zhì)等的特殊規(guī)則。最重要的是,你應該記住這些:
      1、你只能使用從“output”表引用產(chǎn)生的列引用
      2、如果你有GROUP BY語句,你只可能從該語句或聚合函數(shù)引用列
      3、當你沒有GROUP BY語句時,你可以用窗口函數(shù)替代聚合函數(shù)
      4、如果你沒有GROUP BY語句,你就不能將聚合函數(shù)與非聚合函數(shù)結(jié)合起來
      5、這有一些關(guān)于在聚合函數(shù)包裝常規(guī)函數(shù)的規(guī)則,反之亦然
      6、還有…
      嗯,這有很多復雜的規(guī)則。他們可以填補另一個教程。例如,之所以你不能將聚合函數(shù)與非聚合函數(shù)結(jié)合起來投影到?jīng)]有GROUP BY的SELECT語句中是因為:
      1、憑直覺,沒有任何意義。
      2、對一個SQL初學者來說,直覺還是毫無幫助的,語法規(guī)則則可以。SQL:1999年引入了分組集,SQL:2003引入了空分組集GROUP BY()。每當存在沒有顯式GROUP BY語句的聚合函數(shù)時就會應用隱式的空分組集(規(guī)則2)。因此,最初關(guān)于邏輯順序的那個規(guī)則就不完全正確了,SELECT的投影也會影響前面的邏輯結(jié)果,但語法語句GROUP BY卻不受影響。
      是不是有點迷糊?其實我也是,讓我們看一些簡單的吧。
      從中我們學到了什么呢?
      在SQL語句中,SELECT語句可能是最復雜的語句之一,即使它看起來是那么的簡單。所有其他語句只不過是從這個到另一個表引用的的輸送管道。通過將它們完全轉(zhuǎn)化,后期地對它們應用一些規(guī)則,SELECT語句完完全全地攪亂了這些表引用的美。
      為了了解SQL,重要的是要理解其他的一切,都要嘗試在SELECT之前解決。即便SELECT在語法順序中排第一的語句,也應該將它放到最后。
      10.相對簡單一點的SQL DISTINCT,UNION,ORDER BY,和OFFSET
      看完復雜的SELECT之后,我們看回一些簡單的東西。
      集合運算(DISTINCT和UNION)
      排序操作(ORDER BY,OFFSET..FETCH)
      集合運算
      集合運算在除了表其實沒有其他東西的“集”上操作。嗯,差不多是這樣,從概念上講,它們還是很容易理解的
      DISTINCT投影后刪除重復項。
      UNION求并集,刪除重復項。
      UNION ALL求并集,保留重復項。
      EXCEPT求差集(在第一個子查詢結(jié)果中刪除第二個子查詢中也含有的記錄刪除),刪除重復項。
      INTERSECT求交集(保留所有子查詢都含有的記錄),刪除重復項。
      所有這些刪除重復項通常是沒有意義的,很多時候,當你想要連接子查詢時,你應該使用UNION ALL。
      排序操作
      排序不是一個關(guān)系特征,它是SQL僅有的特征。在你的SQL語句中,它被應用在語法排序和邏輯排序之后。保證可以通過索引訪問記錄的唯一可靠方法是使用ORDER BY a和OFFSET..FETCH。所有其他的排序總是任意的或隨機的,即使它看起來像是可再現(xiàn)的。
      OFFSET..FETCH是唯一的語法變體。其他變體包括MySQL'和PostgreSQL的LIMIT..OFFSET,或者SQL Server和Sybase的TOP..START AT(這里)。
      讓我們開始應用吧
      跟其他每個語言一樣,要掌握SQL語言需要大量的實踐。上述10個簡單的步驟將讓你每天編寫SQL時更有意義。另一方面,你也可以從常見的錯誤中學習到更多。下面的兩篇文章列出許多Java(和其他)開發(fā)者寫SQL時常見的錯誤:
      · 10 Common Mistakes Java Developers Make when Writing SQL
      · 10 More Common Mistakes Java Developers Make when Writing SQL

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

    不要急于切換到Java 8的6個原因

     Java 8是極好的。不過我們在嘗完鮮了之后,也開始對它持懷疑的態(tài)度。所有好的東西都是有代價的,在這篇文章中,我會分享Java 8的主要的幾個難點。在你放棄Java 7升級到8之前,你最好確保自己知道這些。
      并行流會影響性能
      Java 8的所承諾的并行處理是最受期待的新特性之一。集合以及流上的.parallelStream()方法就是實現(xiàn)這點的。它將問題分解成子問題,然后分別運行在不同的線程上,它們可能會被分配到不同的CPU核上,當完成之后再組合起來。這些全都是在底層通過fork/join框架來實現(xiàn)的。好的,聽起來很酷吧,在多核環(huán)境下的大數(shù)據(jù)集上,這么做肯定能提升操作速度的,對吧?
      不,如果你用的不對的話,這么做可能會讓你的代碼變得更慢。在我們運行的基準測試上大概是慢了15%左右,而且還有可能會更糟。假設我們已經(jīng)是運行在多核環(huán)境中了,我們又使用了.parallelStream(),將更多的線程加入了線程池中。這很可能會超出我們的核數(shù)的處理能力,并且由于上下文切換,會導致性能出現(xiàn)下降。
      下面是我們的一個性能變差的基準測試,它是要將一個集合分到不同的組里(素數(shù)或者非素數(shù)):
      Map<Boolean, List<Integer>> groupByPrimary = numbers
      .parallelStream().collect(Collectors.groupingBy(s -> Utility.isPrime(s)));
      還有別的原因可能會讓它變得更慢。考慮下這種情況,假設我們有多個任務要完成,其中一個可能花費的時間比其它的更長。將它用.parallelStream() 進行分解可能會導致更快的那些任務完成的時間往后推遲。看下Lukas Krecan的這篇文章,里面有更多的一些例子以及代碼。
      診斷:并行處理帶來好處的同時也帶來了許多額外的問題。當你已經(jīng)是處于一個多核環(huán)境中了,你要時刻牢記這點,并要弄清楚事情表面下所隱藏的本質(zhì)。
      Lambda表達式的負作用
      Lambda。喔,Lambda。盡管沒有你,我們也什么都可以做,但是你讓我們變得更優(yōu)雅,減少了許多樣板代碼,因此大家都很容易會喜歡上你。假設一下早上我起床了想要遍歷世界杯的一組球隊,然后計算出它們的長度:
      List lengths = new ArrayList();
      for (String countries : Arrays.asList(args)) {
      lengths.add(check(country));
      }
      如果有了Lambda我們就可以使用函數(shù)式了:
      Stream lengths = countries.stream().map(countries -> check(country));
      這太牛了。盡管很多時候它都是件好事,不過把Lambda這樣的新元素增加到Java中使得它有點偏離了最初的設計規(guī)范。字節(jié)碼是完全面向?qū)ο蟮模瑫r這個游戲里又帶上了lambda,實際的代碼和運行時之間的差別變得越來越大了。可以讀下Tal Weiss的這篇文章,了解更多關(guān)于lambda表達式的一些陰暗面。
      最后,這意味著你所寫的和你所調(diào)試的完全是兩個不同的東西。棧信息會變得越來越大,這使得你調(diào)試代碼變得更加費勁了。
      將空串增加到列表里,原先只是這么簡單的一個棧信息:
      at LmbdaMain.check(LmbdaMain.java:19)
      at LmbdaMain.main(LmbdaMain.java:34)
      現(xiàn)在變成了:
    at LmbdaMain.check(LmbdaMain.java:19)
    at LmbdaMain.lambda$0(LmbdaMain.java:37)
    at LmbdaMain$$Lambda$1/821270929.apply(Unknown Source)
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
    at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.LongPipeline.reduce(LongPipeline.java:438)
    at java.util.stream.LongPipeline.sum(LongPipeline.java:396)
    at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
    at LmbdaMain.main(LmbdaMain.java:39)
      lambda表達式引起的另一個問題就是重載:由于lambda的參數(shù)必須得強制轉(zhuǎn)化成某個類型才能進行方法調(diào)用,而它們可以轉(zhuǎn)化成好幾個類型,這可能會導致調(diào)用發(fā)生歧義。Lukas Eder通過代碼示例說明了這點。
      診斷:記住這點,棧跟蹤信息可能會成為一種痛苦,不過這并不會阻擋我們使用lambda的腳步。

      默認方法使人困惑
      默認方法使得接口方法的默認實現(xiàn)成為了可能。這的確是Java 8帶來的一個非常酷的新特性,但是它多少影響了我們之前所習慣的做事的方式。那為什么還要引入它呢?什么時候不應該使用它?
      默認方法背后最大的動機應該就是如果我們需要給現(xiàn)有的一個接口增加方法的話,我們可以不用重寫接口的實現(xiàn)。這使得它可以兼容老的版本。比如說,下面是從Oracle官方的一個Java教程中拿過來的一段代碼,它是要給一個指定的時區(qū)添加某個功能:
    public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
    try {
    return ZoneId.of(zoneString);
    } catch (DateTimeException e) {
    System.err.println("Invalid time zone: " + zoneString +
    "; using default time zone instead.");
    return ZoneId.systemDefault();
    }
    }
    default public ZonedDateTime getZonedDateTime(String zoneString) {
    return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
    }
      問題解決了。是嗎?但默認方法將接口及實現(xiàn)弄得有點混淆。類型結(jié)構(gòu)自己是不會糾纏到一起的,所以現(xiàn)在我們得好好馴服下這個新生物了。可以讀下RebelLabs的Oleg Shelajev的這篇文章。
      診斷:當你掄起錘子的時候看誰都像顆釘子,記住了,要堅持原始的用例,將一個現(xiàn)有的接口重構(gòu)成一個新的抽象類是不會有什么用處的。
      下面講的這些,要么是漏掉的,要么是該刪除卻仍在的,或者是還沒有完全實現(xiàn)的:
      為什么是Jigsaw
      Jigsaw項目的目標是使得Java可以模塊化,并將JRE分解成能互相協(xié)作的不同組件。項目的初衷是希望Java可以更好,更快,更強地進行嵌入。我已經(jīng)盡量避免提起“物聯(lián)網(wǎng)”了,但剛才實際已經(jīng)說到了。減少JAR包的大小,提升性能,提高安全性,這些也是這個項目的一些愿景。
      那么它怎么樣了?Jigsaw目前已經(jīng)通過了探索性的階段,進入了第二階段了,目前將致力于設計及實現(xiàn)能達到上線質(zhì)量的產(chǎn)品,Oracle的首席架構(gòu)師Mark Reinhold如是說。這個項目原本是計劃隨著Java8發(fā)布的,后來被推遲到了Java 9,這也是9中倍受期待的新特性之一。
      遺留的問題
      受檢查異常
      大家都不喜歡模板代碼,這也是為什么lambda會如此流行的原因之一。想像一下異常的樣板代碼吧,不管你是不是需要捕獲或者處理這些受檢查異常,你都得去捕獲它。盡管是根本不可能發(fā)生 的事情,就像下面這個一樣,它壓根兒就不會發(fā)生 :
      try {
      httpConn.setRequestMethod("GET");
      }?catch (ProtocolException pe) { /* Why don’t you call me anymore? */ }
      基礎類型
      它們還在這里,要想正確地使用它們簡直是種痛苦。正是它使得Java無法成為一門純粹的面向?qū)ο蟮木幊陶Z言,并且其實上移除它們對性能也沒有太大的影響。新的JVM語言里也都沒有基礎類型。
      操作符重載
      Java之父James Gosling曾在一次采訪中說道:“我沒有采用操作符重載這完全是我個人的喜好,因為我看過太多人在C++中濫用它了”。這也有一定的道理,不過也有不少反對的聲音。別的JVM語言也提供了這一特性,但另一方面,它可能會導致下面這樣的代碼:
      javascriptEntryPoints <<= (sourceDirectory in Compile)(base =>
      ((base / "assets" ** "*.js") --- (base / "assets" ** "_*")).get
      )
      這是Scala的Play框架中的一行真實的代碼,我已經(jīng)有點崩潰了。
      診斷:這些真的算是問題嗎?我們都有自己的怪癖,這些也算是Java的吧。未來的版本可能會有驚喜,這些也可能會變,但是向后兼容的問題也在那里等著我們了。
      函數(shù)式編程
      Java之前也可以進行函數(shù)式編程,雖然說有點勉強。Java 8通過lambda以及別的一些東西改進了這一狀態(tài)。這確實是最受歡迎的特性,不過并沒有之前傳說中的那么大的變化。它是比Java 7要優(yōu)雅多了,不過要想成為真正的函數(shù)式語言還有很長的路要走。
      關(guān)于這個問題最激烈的評論應該是來自Pierre-yves Saumont 的這一系列的文章了,他詳細比較了函數(shù)式編程的范式和Java的實現(xiàn)方式之間的區(qū)別。
      那么該用Scala還是Java?Java采用了更現(xiàn)代的函數(shù)式范式也算是對Scala的一種認可,后者提供lambda也有一段時間了。lambda確實是獨領風騷,但是還有許多別的特性比如說trait,惰性求值,不可變性等,它們也是Scala不同于Java之處。
      診斷: 不要被lambda分心了,Java 8算不算函數(shù)式編程仍在爭論當中。

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

    Python fabric遠程自動部署簡介

     Fabric是一個Python(2.5-2.7)庫,用于簡化使用SSH的應用程序部署或系統(tǒng)管理任務。
      它提供的操作包括:執(zhí)行本地或遠程shell命令,上傳/下載文件,以及其他輔助功能,如提示用戶輸入、中止執(zhí)行等。
      本文主要介紹CentOS 6.3上使用fabric進行自動部署的基本方法。
      1.    環(huán)境部署
      本節(jié)主要介紹python版本升級,pip及fabric部署方法。
      1.1.    Python版本升級
      CentOS 6.3自帶的Python版本為2.6,首先需要升級到2.7版本。由于舊版本的Python已被深度依賴,所以不能卸載原有的Python,只能全新安裝。
      1. 下載Pyhon,選擇下載Gzipped source tar ball (2.7.6) (sig),網(wǎng)址:https://www.python.org/download/releases/2.7.6
      2. 解壓安裝,命令如下
      tar -xvf Python-2.7.6.tgz
      cd Python-2.7.6
      ./configure --prefix=/usr/local/python2.7
      make
      make install
      3. 創(chuàng)建鏈接來使系統(tǒng)默認python變?yōu)閜ython2.7
      ln -fs /usr/local/python2.7/bin/python2.7 /usr/bin/python
      4. 查看Python版本
      python –V
      5. 修改yum配置(否則yum無法正常運行)
      vi /usr/bin/yum
      將第一行的#!/usr/bin/python修改為系統(tǒng)原有的python版本地址#!/usr/bin/python2.6
      至此CentOS6.3系統(tǒng)Python已成功升級至2.7.6版本。
      1.2.    安裝pip
      Pip是一個安裝和管理python包的工具。
      安裝方法如下:
      1. 下載pip,地址https://raw.github.com/pypa/pip/master/contrib/get-pip.py
      2. 執(zhí)行安裝命令
      python get-pip.py
      3. 創(chuàng)建連接(否則會報錯提示“命令不存在”)
      ln -s /usr/local/python2.7/bin/pip /usr/bin/pip
      1.3.    安裝fabric
      1. 執(zhí)行安裝命令
      pip install fabric
      2. 創(chuàng)建連接(否則會報錯提示“命令不存在”)
      ln -s /usr/local/python2.7/bin/fab /usr/bin/fab
      2.    腳本編寫
      本節(jié)對fabric用法進行簡單介紹,并提供實例以供參考。
      2.1.    Hello,fab
      1. 在當前目錄下新建文件fabfile.py,輸入內(nèi)容如下
      def hello():
      print("Hello fab!")
      2. 執(zhí)行命令fab hello,結(jié)果如下
      # fab hello
      Hello fab!
     3. 文件名不為fabfile.py時需進行指定
      # mv fabfile.py test.py
      # fab hello
      Fatal error: Couldn't find any fabfiles!
      Remember that -f can be used to specify fabfile path, and use -h for help.
      # fab -f test.py hello
      Hello fab!
      4. 參數(shù)傳遞
      #vi fabfile.py
      def hello(name):
      print 'Hello %s!'%name
      # fab hello:name=fab
      Hello fab!
      # fab hello:fab
      Hello fab!
      2.2.    本地操作
      執(zhí)行本地操作命令使用local
      1. fabfile.py腳本內(nèi)容如下
      from fabric.api import local
      def test():
      local('cd /home/')
      local('ls -l|wc -l')
      2. 執(zhí)行命令fab test,結(jié)果如下
      # fab test
      [localhost] local: cd /home/
      [localhost] local: ls -l|wc -l
      2.3.    遠程操作
      執(zhí)行遠程操作命令使用run
      1. fabfile.py腳本內(nèi)容如下
      from fabric.api import cd,run,env,hosts
      env.hosts=['192.168.85.99:22','192.168.85.101:22']
      env.password='test'
      def test():
      with cd('/home'):
      run("du -sh")
      2. 執(zhí)行命令fab test,結(jié)果如下
      # fab test
      [192.168.85.99:22] Executing task 'test'
      [192.168.85.99:22] run: du -sh
      [192.168.85.99:22] out: 392G      .
      [192.168.85.99:22] out:
      [192.168.85.101:22] Executing task 'test'
      [192.168.85.101:22] run: du -sh
      [192.168.85.101:22] out: 5.6G     .
      [192.168.85.101:22] out:
      Disconnecting from 192.168.85.99... done.
      Disconnecting from 192.168.85.101... done.
      3. 多服務器混合,需要在不同服務器進行不同操作時,可參考如下腳本
      from fabric.api import env,roles,run,execute
      env.roledefs = {
      'server1': ['root@192.168.85.99:22',],
      'server2': ['root@192.168.85.100:22', ]
      }
      env.password = 'test'
      @roles('server1')
      def task1():
      run('ls /home/ -l | wc -l')
      @roles('server2')
      def task2():
      run('du -sh /home')
      def test():
      execute(task1)
      execute(task2)
      結(jié)果如下
      # fab test
      [root@192.168.85.99:22] Executing task 'task1'
      [root@192.168.85.99:22] run: ls /home/ -l | wc -l
      [root@192.168.85.99:22] out: 27
      [root@192.168.85.99:22] out:
      [root@192.168.85.100:22] Executing task 'task2'
      [root@192.168.85.100:22] run: du -sh /home
      [root@192.168.85.100:22] out: 1.4G   /home
      [root@192.168.85.100:22] out:
      Disconnecting from 192.168.85.99... done.
      Disconnecting from 192.168.85.100... done.

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

    使用Gradle運行集成測試

     如果Gradle構(gòu)建的項目是一個web項目的話,里面可能包含一些集成測試和功能性測試。這些測試和單元測試不同之處是在運行之前要先在本地將web服務啟動起來,并且跑完測試后能夠自動的關(guān)閉web服務。
      在本地啟動web服務我們可以使用Gradle內(nèi)置的jetty插件。jetty是一個輕量級的web容器,其執(zhí)行速度快,配置簡單,遠程調(diào)試方便。啟用jetty只需在build.gradle中加入對這個插件的引用。
      apply plugin: 'jetty'
      之后可以配置war包的名稱,啟動的端口等屬性。
      apply plugin: 'jetty'
      httpPort = 9876
      [jettyRun, jettyRunWar, jettyStop]*.stopPort = 9966
      [jettyRun, jettyRunWar, jettyStop]*.stopKey = 'stopKey'
      我們需要將集成測試與一般的單元測試分開。因為單元測試并不需要事先啟動web服務,保證其執(zhí)行速度快,能夠得到更快的反饋。一般做法是單元測試后綴名為Test.java,集成測試后綴名為IntegrationTest.java。
      配置單元測試執(zhí)行的測試集合。
      test {
      include '**/*Test.class'
      exclude '**/*IntegrationTest.class'
      }
      然后新建一個Task,用于運行集成測試。
    build.gradle
    task intTest(type: Test, dependsOn: test) {
    include '**/*IntegrationTest.class'
    doFirst {
    jettyRun.daemon = true
    jettyRun.execute()
    }
    doLast {
    jettyStop.execute()
    }
    }
      上述代碼首先是創(chuàng)建一個名為intTest的task,其類型為Test,依賴于test task。該集成測試只會運行后綴名為IntegrationTest的測試類。在運行測試之前,首先采用后臺模式啟動jetty服務器,運行完測試后再調(diào)用jettyStop task停止jetty服務。
      為了使我們在運行g(shù)radle build時也會運行intTest task,可以添加對intTest的依賴。
      build.dependsOn intTest
      這樣在運行g(shù)radle build時也會運行集成測試。并且在集成測試前后web服務會自動的啟動和關(guān)閉。

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

    Asp.net與Flex交互測試記錄

      一、利用asp.net為Flex提供數(shù)據(jù)服務,flex為前端表現(xiàn)。
      二、flex通過三種方式四種代碼實現(xiàn)來取數(shù)據(jù)。分別為
      HttpService、
      WebService、
      RemoteObject、
      RemoteObjectAMF0。
      三、Project文件夾中的
      Vs2010Service提供HttpService、Webservice服務;
      Vs2008RemoteObject提供RemoteObject服務。
      四、FluorineFx.NET+RemoteObjectAMF0文件為附加文件。
      五、<sessionState cookieless="AutoDetect"></sessionState>
      設置可兼容客戶端禁用Cookie(要在Flex項目中傳遞回sessionid)
      六、asmx中使用session需要[WebMethod(EnableSession = true)] 如此設置。
      七、安裝FluorineFx.NET+RemoteObjectAMF0文件下的setup(FluorineFx.NET).exe
      可以將項目模板集成到2005和2008中,不支持vs2010。
      八、使用七中的模板建立普通網(wǎng)站(FluorineFx ASP.NET Web Site)項目。
      將Console.aspx設為啟動頁,可進行類中的方法測試
      九、使用RemoteObjectAMF0時將renaun_com_RemoteObjectAMF0.zip解壓把src下的
      com文件夾整體復制到flex項目中;
      注意路徑與mxml同路徑;
      RemoteObjectAMF0.as中的override public function setCredentials( username:String, password:String):void)修改成override public function setCredentials( username:String, password:String,charset:String=null ):void)
      添加xmlns:renaun="com.renaun.rpc.*"到<mx:Application ……中。
      十、使用普通RemoteObject在mxml的同目錄下添加services_config.xml文件內(nèi)容如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <services-config>
    <services>
    <service id="remoting-service"
    class="flex.messaging.services.RemotingService"
    messageTypes="flex.messaging.messages.RemotingMessage">
    <destination id="fluorine">
    <channels>
    <channel ref="my-amf"/>
    </channels>
    <properties>
    <source>*</source>
    </properties>
    </destination>
    </service>
    </services>
    <channels>
    <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint uri="http://localhost:12432/ReomteFlex/Gateway.aspx" class="flex.messaging.endpoints.AMFEndpoint"/>
    </channel-definition>
    </channels>
    </services-config>
      注:http://localhost:12432/ReomteFlex/Gateway.aspx隨項目啟動的端口變化。
      之后,F(xiàn)lex項目右鍵-屬性-Flex compiler-compiler參數(shù)(-locale en_US -services "services_config.xml")

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

    最糟糕的編程面試題

     多年前,我寫了一篇關(guān)于我所鄙視的某些類型的面試題。今天我想討論一個更具體的問題,而不僅是類型。我從來沒有問過自己這個問題,但我已經(jīng)看有人在實際面試中提這個問題,我正式提名它為最糟糕的編程面試題。
      在之前的公司里,有個同事經(jīng)常問這個問題,那次是我第一次在面試時聽到它。這家公司結(jié)對面試,兩個工程師,一個候選人。有一天,我和他作為一對,去面試一些杯具的應聘者。我覺得應聘者其實表現(xiàn)不錯,然后我的同事拋出了這個問題。應聘者結(jié)結(jié)巴巴地回答,很明顯他囧了。在面試后的聚會,所有面試他的工程師都向他豎起了大拇指,只有我搭檔反對雇用他,只因“任何稱職的工程師都應該能夠回答它”。他確鑿地說不能跟那個人共存。值得一提的是,這個故事有個大團圓結(jié)局,我們不顧我搭檔的抗議,還是招了那個人,并在幾個月內(nèi)炒了我搭檔,而那個應聘者仍在那家公司,干得好好的。
      無論如何,我認為有這個問題的面試都是“有問題”的,所以我想在這里說明為什么它幾乎是恐怖的一個面試題:
      寫一個能檢測鏈表是否存在環(huán)路的函數(shù)。
      看來像是的基本算法問題,對嗎?站起來,在白板上寫函數(shù)。很正常,對嗎?不是,這是不對的,別這么干。
      1.這完全是不恰當?shù)摹?/strong>
      這是一個工作面試。你有一個實時的環(huán)境,跟你說話的人在面試著。緊張是很正常的。而那種帶有“靈關(guān)一閃”的智力題是最壞的問題。你的大腦將致力于思考“該死,我正搞砸這個面試”而不是關(guān)注手邊的問題。
      人們喜歡“看到應聘者如何思考”,但智力題無助于此。正因為它是智力題。你只能希望智力題給你“恍然大悟”。有時我聽到人們想知道應聘者如何處理壓力,但你應該知道,面試中本來就是有壓力的。
      問人難題完全是浪費時間,這樣做只是考察到應聘者以前有沒看過這題。或者說考察了他們的演技(當他們聽說過這問題并知道答案卻假裝沒聽說,然后裝模作樣逐步推導以得出答案)。
      這條問題是最浪費時間的。你還問為什么?好,想象一下如果一個人真的是第一次聽到這個問題,然后你期望他推出答案。
      對于這條題,一般來說的“正確”的答案是龜兔算法,在鏈表頭放兩個指針,一個是一步走兩個節(jié)點,另一個則一步一點;如果走著走著指針指向同一個節(jié)點,那就代表有環(huán)路了。
      當然,還有更簡單的答案,例如,將所有走過的節(jié)點標記為“走過”,或者從每個點出發(fā),看能不能回答該點,又或者在遍歷過程中做哈希,看有沒有重復。但當你拋出這些答案時,面試官又會加條件,要求使用更少的內(nèi)存或時間或不能改原本的數(shù)據(jù)結(jié)構(gòu)。而最佳的答案就是龜兔。
      是否一開始就該考慮到這么多?無論如何,看來你很覺得你能考慮周到。鏈表這種數(shù)據(jù)結(jié)構(gòu)是1955年由Allen Newell,Cliff Shaw 和 Herbert A. Simon 發(fā)現(xiàn)的。而“正確”的鏈表環(huán)路檢測算法,則叫做“Floyd 環(huán)查找算法”,以紀念發(fā)現(xiàn)者Robert W. Floyd,那是1967年的事。
      1955至1967之間,這個問題是開放的,就是說,無數(shù)考數(shù)學或計算機博士的人都可能將它寫進論文里。即使那么多人在鉆研著,這個問題還是12年無解。
      你真的覺得你行嗎,用20分鐘,僅憑超越所有學者的壓力,搞定這個曾經(jīng)12年無解的難題?看來是不行的,你覺得行,只不過是因為你看過答案,然后在面試中,你”似曾相識“、”靈關(guān)一閃“。
      2.這完全是不切實際的
      如果上面給的理由還不能讓你恥笑那個爛問題,那你再想想,這個問題是否真的有用于日常工作。
      我的意思是:你怎么會在實際中碰到有環(huán)的鏈表?
      我并不是說叫你故意搞出一個有指回自身的鏈表,而是說,無端端會有這樣的東西?
      鏈表這種數(shù)據(jù)結(jié)構(gòu)不是抽象的東西,棧或隊列才是,你或者會在一些抽象的數(shù)據(jù)結(jié)構(gòu)中用到鏈表這種實在的東西。例如棧,你就用來壓入,彈出,查看,是吧?那怎么會造成環(huán)呢?沒有人想把它搞成一團的吧?
      即使你自己寫個鏈表,你也不會想做出這種樣子。看下java的LinkedList類,你是無法從外部去操控它的next和prev的,你只能取得第一個或最后一個,添加節(jié)點到某一位置,按位置或值刪除節(jié)點。
     看下java源碼就知道,真的沒有:
    private static class Entry <E> {
    E element;
    java.util.LinkedList.Entry<E> next;
    java.util.LinkedList.Entry<E> previous;
    Entry(E e, java.util.LinkedList.Entry<E> entry, java.util.LinkedList.Entry<E> entry1) {
    /* compiled code */
    }
    }
      它是一個私有靜態(tài)類,你無法從外部實例化它。你不能直接操控next和prev,因為它們倆代表了鏈表的狀態(tài),它們就該這樣被封裝起來。
      如果你真的把鏈表搞成有環(huán)了,那說明你寫錯。寫錯的話,你最好重新寫對它,而不是寫個“檢測環(huán)”的方法。
      “檢測環(huán)”的方法就該這樣寫:
    public class LinkedList {
    public boolean containsCycle() {
    return false;
    }
    }
      如果你的鏈表寫對的話,“龜兔算法”返回的結(jié)果也跟這個方法一樣。
      現(xiàn)實中你是很少有機會親手寫個鏈表的,即使有,你也別寫個能造成環(huán)的方法。造成環(huán)的方法,只能是“留后門”,“元編程”,“反射”。既然是這樣故意的話,那么繞過你的“檢測環(huán)”也是輕而易舉的。
      結(jié)論
      很多面試題,都中了以上其中一點,太過困難或者與工作無關(guān)。
      而這個問題,兩點都中了。
      如果有人給到你滿意的答案,就說明那個人死記硬背,無他。因回答不了而被你否決的人,說不定還比你更適合這份實務。
      鏈表環(huán)路檢測:別問了。
      更新:有位評論者說如果問題問的是有向圖,且每個節(jié)點的出度最多只有,即是問“檢測這個有向圖有沒有環(huán)”。搞圖的話,你確實可能會向API用戶提供修改每點的指向的方法,這看上去符合實際。但是,還是那句話,你只是在考察應聘者把CS課程記住了多少,或者你只想隨便問問,又或者你想聽聽他說除了龜兔算法以外的低效算法。

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

    Linux上搭建nginx,及簡單配置

     在上家公司都是運維安裝nginx,到新公司后代碼開發(fā)完成部署測試服務器要求自己裝nginx,研究了好久安裝好之后,到正式上線還要自己安裝,索性把安裝步驟自己記載下來(好大一部分都是在網(wǎng)站找的)。
      一,安裝
      1.選定源碼目錄
      可以是任何目錄,本文選定的是/usr/local/src
      cd/usr/local/src
      2.安裝PCRE庫
      ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/下載最新的PCRE源碼包,使用下面命令下載編譯和安裝PCRE包:
    cd/usr/local/src
    wgetftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.33.tar.gz
    tar-zxvfpcre-8.21.tar.gz
    cdpcre-8.21
    ./configure
    make
    makeinstall
      3.安裝zlib庫
      http://zlib.net/zlib-1.2.8.tar.gz下載最新的zlib源碼包,使用下面命令下載編譯和安裝zlib包:
    cd/usr/local/src
    wgethttp://zlib.net/zlib-1.2.8.tar.gz
    tar-zxvfzlib-1.2.8.tar.gz
    cdzlib-1.2.8
    ./configure
    make
    makeinstall
      4.安裝ssl(某些vps默認沒裝ssl)
      cd/usr/local/src
      wgethttp://www.openssl.org/source/openssl-1.0.1c.tar.gz
      tar-zxvfopenssl-1.0.1c.tar.gz
      5.安裝nginx
      Nginx一般有兩個版本,分別是穩(wěn)定版和開發(fā)版,您可以根據(jù)您的目的來選擇這兩個版本的其中一個,下面是把Nginx安裝到/usr/local/nginx目錄下的詳細步驟:
    cd/usr/local/src
    wgethttp://nginx.org/download/nginx-1.4.2.tar.gz
    tar-zxvfnginx-1.4.2.tar.gz
    cdnginx-1.4.2
    ./configure--sbin-path=/usr/local/nginx/nginx\
    --conf-path=/usr/local/nginx/nginx.conf\
    --pid-path=/usr/local/nginx/nginx.pid\
    --with-http_ssl_module\
    --with-pcre=/usr/local/src/pcre-8.21\
    --with-zlib=/usr/local/src/zlib-1.2.8\
    --with-openssl=/usr/local/src/openssl-1.0.1c
    make
    makeinstall
    --with-pcre=/usr/src/pcre-8.21指的是pcre-8.21的源碼路徑。
    --with-zlib=/usr/src/zlib-1.2.7指的是zlib-1.2.7的源碼路徑。
      安裝成功后/usr/local/nginx目錄下如下
    fastcgi.confkoi-winnginx.conf.default
    fastcgi.conf.defaultlogsscgi_params
    fastcgi_paramsmime.typesscgi_params.default
    fastcgi_params.defaultmime.types.defaultuwsgi_params
    htmlnginxuwsgi_params.default
    koi-utfnginx.confwin-utf
      6.啟動
      確保系統(tǒng)的80端口沒被其他程序占用,運行/usr/local/nginx/nginx命令來啟動Nginx,
      netstat-ano|grep80
      如果查不到結(jié)果后執(zhí)行,有結(jié)果則忽略此步驟(ubuntu下必須用sudo啟動,不然只能在前臺運行)
      sudo/usr/local/nginx/nginx
      打開瀏覽器訪問此機器的IP,如果瀏覽器出現(xiàn)Welcometonginx!則表示Nginx已經(jīng)安裝并運行成功。
      二,簡單配置(nginx后掛resin或者tomcat)
      (標紅部分為自己新加的配置)
      注:只是簡單的配置
    http{
    upstreammgame-crm{
    server10.10.0.103:9080;
    server10.10.0.104:9080;
    }
    includemime.types;
    default_typeapplication/octet-stream;
    #log_formatmain'$remote_addr-$remote_user[$time_local]"$request"'
    #'$status$body_bytes_sent"$http_referer"'
    #'"$http_user_agent""$http_x_forwarded_for"';
    #access_loglogs/access.logmain;
    sendfileon;
    #tcp_nopushon;
    #keepalive_timeout0;
    keepalive_timeout65;
    #gzipon;
    server{
    listen80;
    server_namelocalhost;
    #charsetkoi8-r;
    #access_loglogs/host.access.logmain;
    location/{
    roothtml;
    indexindex.htmlindex.htm;
    proxy_passhttp://mgame-crm;
    proxy_redirectoff;
    proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;
    proxy_set_headerX-Real-IP$remote_addr;
    proxy_set_headerHost$http_host;
    access_logoff;
    }
    #error_page404/404.html;
    #redirectservererrorpagestothestaticpage/50x.html
    #
    error_page500502503504/50x.html;
    location=/50x.html{
    roothtml;
    }
    #proxythePHPscriptstoApachelisteningon127.0.0.1:80
    #
    #location~\.php${
    #proxy_passhttp://127.0.0.1;
    #}
    #passthePHPscriptstoFastCGIserverlisteningon127.0.0.1:9000
    #
    #location~\.php${
    #roothtml;
    #fastcgi_pass127.0.0.1:9000;

    posted @ 2014-07-15 10:33 順其自然EVO 閱讀(232) | 評論 (0)編輯 收藏

    我的經(jīng)常使用linux小命令

      這里并非系統(tǒng)具體介紹每個Linux命令,不過記錄本人在平時工作中經(jīng)經(jīng)常使用到的一些比較基礎的命令及相關(guān)的參數(shù),同一時候用了一些簡單的樣例來說明這些命令的用途,以及怎樣用多種命令來實現(xiàn)同一種功能。
      1、ls命令
      要顯示當前文件夾下的文件列表時,我常常就使用ls命令的下面三個參數(shù)。
      -l 使用長列表格式
      -h 文件大小以人可讀的方式打印
      -t 以最后改動時間排序,最新的放在最前
      使用樣例,怎樣顯示當前文件夾下的文件夾?
      方法1: ls -l | grep '^d'
      方法2: ls -l | awk '/^d/'
      2、grep命令
      當須要找出匹配指定模式的文件時,常常會用到grep命令的下面幾個參數(shù)。
      -w 全然匹配整個單詞,而不是字符串的一部分,若要匹配abc,則不會匹配abcd
      -i 忽略大寫和小寫
      -n 顯示指定模式在匹配文件里的行號
      -v 反向匹配,即匹配不符合的行
      -f 從文件里獲取待匹配的模式
      使用樣例:
      grep ^$ file 匹配文件file中的全部空行
      grep -v '^$' file 匹配文件file中的全部非空行
      grep '[^^$]' file 匹配文件file中的全部非空行
      grep -vf t2 t1 獲取t1中跟t2數(shù)據(jù)不匹配的數(shù)據(jù),即獲取在t1,但不在t2的數(shù)據(jù)
      正則表達式[^$]表示匹配空行,前面加上^即表示不匹配空行
      3、排序去重命令 sort vs uniq
      sort 命令用來對數(shù)據(jù)進行排序。
      -t 用于指定域的分隔符
      -n 以數(shù)字方式進行比較,而不是字符比較
      -r 反向排序
      -u 去除反復的行
      -k 以指定的域開始進行排序,域從1開始
      +表示以第幾域排序,-表示不以第幾域排序,如 sort +0 -2 +3則表示以第0域開始排序,略過第2域,然后再使用第3域排序
      uniq 用于刪除文本文件里的連續(xù)反復的行,一般使用sort之后再調(diào)用uniq。
      -d 僅顯示反復一次的行
      -c 打印每一反復行出現(xiàn)的次數(shù)
      sort -u 和uniq的差別在于,uniq僅去除連續(xù)反復的行,而sort -u會去除整個文本中全部反復的行,比如,
      #源文件file1中的內(nèi)容
      hello world
      Good morning
      Good morning
      hello world
      #使用sort -u < file1的結(jié)果例如以下:
      hello world
      Good morning
      使用uniq < file1的結(jié)果例如以下:
      hello world
      Good morning
      hello world
      4、tr命令
      當須要進行一些簡單的字符串替換和刪除時,tr命令就會顯得很實用。
      比如,以下的tr操作都是沒有直接改動源文件,改動則須要文件重定向
      tr 'A-Z' 'a-z' < file 將字符串的大寫字母都轉(zhuǎn)為小寫字母:
      tr -s ' ' ' ' < file 把多個連續(xù)空格替換成單個空格,-s選項可將多個連續(xù)字符替換為一個指定字符
      tr -s '\n' < file 刪除空行
      tr -d '[0-9]' < file 刪除全部數(shù)字,-d選項能夠刪除指定的字符
     5、tail命令
      tail命令用于顯示文件末尾指定區(qū)域的內(nèi)容,如tail -10 file, 表示顯示文件file最后10行內(nèi)容,tail命令有非常多參數(shù),當中有一個常常使用并且非常好用的參數(shù) "-f":
      tail -f 動態(tài)顯示文件新增的內(nèi)容
      該參數(shù)作用是不返回文件結(jié)束符,并動態(tài)顯示文件新增的內(nèi)容,須要結(jié)束時,須要用戶手動進行中斷。這個命令在顯示日志的時候作用就很明顯,對于一個執(zhí)行中的server,可能會不斷將server當前執(zhí)行狀態(tài)和錯誤狀態(tài)寫入日志文件,使用tail -f,將會以一定的時間實時追蹤該文件的全部更新。
      6、find命令
      在查找文件文件的時候,首先會想到是使用find命令。
      -name 依照文件名稱查找文件
      比如,查找當前文件夾下名字以cpp結(jié)尾的文件
      find . -name "*cpp" | xargs grep "abc"
      有些系統(tǒng)對參數(shù)的長度有限制,xargs命令的作用是將參數(shù)列表轉(zhuǎn)換成小塊分段傳遞給其它命令,以避免參數(shù)列表過長的問題。上面的find中,當前文件夾下可能包括非常多名字以cpp結(jié)尾的文件,因此為了避免“參數(shù)列太長”或“參數(shù)列溢出“的錯誤,使用xargs來接收find命令的輸出。
      7、alias命令
      alias命令用于設置命令的別名。利用alias能夠把非常長的命令變成隨意簡短的命令。
      若要加入自己的alias,格式例如以下
      alias ll="ls -lht"
      上述加入alias的操作,在用戶退出后就變?yōu)闊o效了,若要永久生效,能夠改動配置文件~/.bashrc文件(僅改動用戶自己),在文件最后面加上你自定義的alias,如:
      alias la="ls -al --color=auto"
      本次改動,要在下次登錄的時候才干生效。若要立即生效,能夠輸入:
      source ~/.bashrc
      8、進程相關(guān)命令
      ps命令用于查看當前執(zhí)行的進程。
      ps -ef 顯示系統(tǒng)執(zhí)行的進程
      top 用于查看當前進程執(zhí)行情況,包含內(nèi)存使用、cpu使用量、交換區(qū)使用量等。
      shift + m 能夠按內(nèi)存占用量來排序進程,查找進程內(nèi)存使用量就最實用了
      q 退出
      9、經(jīng)常使用快捷鍵
      Ctrl + z 將當前程序放到后臺并掛起
      Ctrl + d 輸入文件結(jié)束符,在命令行中直接輸入Ctrl + D,即退出shell
      Ctrl + a 跳到命令行的頭部位置
      Ctrl + e 跳到命令行的尾部位置
      Ctrl + w 刪除一個單字(word)
      Ctrl + u 刪除光標到行首的字符
      Ctrl + k 刪除光標到行末的字符
      Ctrl + c 中斷當前程序
      10、任務命令
      命令運行順序
      && 第一個命令成功才運行第二個命令
      || 第一個命令失敗才運行第二個命令
      jobs 查看掛起的當前的任務列表
      fg + N  將第N個任務放到前端,喚醒Ctrl + z掛起的任務
      11、vim命令
      !%xxd 以十六進制的方式查看文件內(nèi)容
      ! 后面加上shell命令就而已運行對應的shell命令
      * 將光標移至下一個匹配的單詞
      # 將光標移至上一個匹配的單詞
      [[ 光標跳到函數(shù)的開頭
      ]] 光標調(diào)到函數(shù)的結(jié)尾說
      [{ 光標跳到上一個作用域的開頭
      ]} 光標跳到下一個作用域的開頭
      ggvG或者ggVG 全選并高亮
      gg=G 對整個文件內(nèi)容進行格式化縮進
      u 撤銷上一個動作
      Ctrl + r 取消上一個撤銷動作
      set scb 同步兩個屏幕的文件,當中一個文件移動,則令一個文件跟著移動,對照兩個文件時經(jīng)常常使用到,解開分屏set scb!
      兩個非常好用的插件ctag和Tlist:
      ctags
      功能是掃描指定的源文件,找出當中所包括的語法元素,并將找到的相關(guān)內(nèi)容記錄下來。記錄的內(nèi)容包括:宏定義、枚舉型、變量的值、函數(shù)的定義、原型和聲明、namespace、typedefs變量 、類、結(jié)構(gòu)、枚舉類型和聯(lián)合 類、結(jié)構(gòu)和聯(lián)合中成員變量或函數(shù)等。通過ctags我們能夠非常easy的找到某個變量或者函數(shù)等在哪個文件定義。
      Tlist
      在當前vim中,新開一個區(qū)域,顯示了當前文件的函數(shù)、類、全局變量等定義,輸入回車就可以跳轉(zhuǎn)到對應內(nèi)容的起始位置。平時在查找某個函數(shù)時,就能夠用到了。
      12、shell中凝視一塊代碼
      行凝視
      shell中默認提供的凝視方法是#,作用是凝視一行,比如
      #這里是一行凝視
      if [ "1" = "2" ]; then
      DoSomething
      fi
      塊凝視
      shell中并沒有提供塊凝視的方法,可是我們能夠使用還有一種方法來實現(xiàn)塊凝視,這樣的叫做here document。here document表示包括的這段內(nèi)容是一個總體數(shù)據(jù)。以下代碼中,兩個document之間的內(nèi)容是一個總體數(shù)據(jù)。
      <<document
      ....
      document
      here document,<<符號表示這是一個文本內(nèi)容,由其后的字符串包括的范圍就是文本的正文,:符號表示空命令,什么都不干,以下的意思就是將一個文本傳給空命令,即對文本不做不論什么處理,間接就等于凝視了
      :<<block
      code
      block
      避免反引號不能被凝視的做法是加上單引號
      :<<block'
      code
      'block
      一些小問題
      問題1: 怎樣刪除文件里的全部空行?
      1、sed '/^$/d' file 對匹配的空行運行刪除操作
      2、awk '/./ {print $0;}' file 匹配除空白換行字符外的全部字符,即匹配非空行
      3、awk '/[^^$]/{ print $0; } file
      問題2: 怎樣刪除文件名稱帶空格的文件,如"a b.html"s?
      1、對空格進行轉(zhuǎn)義,即空格前加上反斜杠,能夠用反斜杠\來屏蔽特殊字符
      2、使用雙引號括住文件名稱
      3、使用單引號括住文件名稱
      問題3:
      一個傻x錯誤,在運行一段代碼后,然后推斷$?是否為0,以決定前面的功能代碼是否運行成功,可是發(fā)現(xiàn)什么情況下都是返回成功,查了好久,原來是在推斷$?之前,使用了echo輸出 $?,所以永遠都是為真了

    posted @ 2014-07-15 10:32 順其自然EVO 閱讀(285) | 評論 (0)編輯 收藏

    Oracle中SQL語句解析的步驟

     我們都知道在Oracle中每條SQL語句在執(zhí)行之前都需要經(jīng)過解析,這里面又分為軟解析和硬解析。那么這兩種解析有何不同之處呢?它們又分別是如何進行解析呢?Oracle內(nèi)部解析的步驟又是如何進行的呢?下面我們就這些話題進行共同探討。
      在Oracle中存在兩種類型的SQL語句,一類為DDL語句,他們是從來不會共享使用的,也就是每次執(zhí)行都需要進行硬解析。還有一類就是DML語句,他們會根據(jù)情況選擇要么進行硬解析,要么進行軟解析。在Oracle 8i OCP教材的023中1-12有說明SQL語句的解析步驟,當一條SQL語句從客戶端進程傳遞到服務器端進程后,需要執(zhí)行如下步驟:
       在共享池中搜索 SQL 語句的現(xiàn)有副本
       驗證 SQL 語句的語法是否準確
       執(zhí)行數(shù)據(jù)字典查找來驗證表和列的定義
       獲取對象的分析鎖以便在語句的分析過程中對象的定義不會改變
       檢查用戶訪問引用方案對象的權(quán)限
       確定語句的最佳執(zhí)行計劃
       將語句和執(zhí)行計劃載入共享的 SQL 區(qū)
      這個先入為主的概念一直占據(jù)著我的腦海,我認為硬解析就是上面幾個步驟。相對于硬解析,軟解析的步驟就是上面第一步找到現(xiàn)有SQL語句的副本后,只需要驗證用戶是否有權(quán)限執(zhí)行就是了,這樣省略上面好幾個步驟,相對硬解析來說性能開銷就非常小了。即使是在論壇上和大家討論時,我也一直堅持這個看法。直到前一天看了Tom的《Effective Oracle By Design》中關(guān)于語句處理的章節(jié)后,我才知道這個自己一直堅持的觀點事實上是錯誤的。
      事實上,在Oracle中SQL語句的解析步驟如下:
      1、語法檢測。判斷一條SQL語句的語法是否符合SQL的規(guī)范,比如執(zhí)行:SQL> selet  *  from emp;我們就可以看出由于Select關(guān)鍵字少了一個“c”,這條語句就無法通過語法檢驗的步驟了。
      2、語義檢查。語法正確的SQL語句在解析的第二個步驟就是判斷該SQL語句所訪問的表及列是否準確?用戶是否有權(quán)限訪問或更改相應的表或列?比如如下語句:
      SQL> select * from emp;
      select * from emp
      *
      ERROR at line 1:
      ORA-00942: table or view does not exist
      由于查詢用戶沒有可供訪問的emp對象,因此該SQL語句無法通過語義檢查。
      3、檢查共享池中是否有相同的語句存在。假如執(zhí)行的SQL語句已經(jīng)在共享池中存在同樣的副本,那么該SQL語句將會被軟解析,也就是可以重用已解析過的語句的執(zhí)行計劃和優(yōu)化方案,可以忽略語句解析過程中最耗費資源的步驟,這也是我們?yōu)槭裁匆恢睆娬{(diào)避免硬解析的原因。這個步驟又可以分為兩個步驟:
      (1、)驗證SQL語句是否完全一致。在這個步驟中,Oracle將會對傳遞進來的SQL語句使用HASH函數(shù)運算得出HASH值,再與共享池中現(xiàn)有語句的HASH值進行比較看是否一一對應。現(xiàn)有數(shù)據(jù)庫中SQL語句的HASH值我們可以通過訪問v$sql、v$sqlarea、v$sqltext等數(shù)據(jù)字典中的HASH_VALUE列查詢得出。如果SQL語句的HASH值一致,那么ORACLE事實上還需要對SQL語句的語義進行再次檢測,以決定是否一致。那么為什么Oracle需要再次對語句文本進行檢測呢?不是SQL語句的HASH值已經(jīng)對應上了?事實上就算是SQL語句的HASH值已經(jīng)對應上了,并不能說明這兩條SQL語句就已經(jīng)可以共享了。我們首先參考如下一個例子:
      假如用戶A有自己的一張表EMP,他要執(zhí)行查詢語句:select * from emp;用戶B也有一張EMP表,同樣要查詢select * from emp;這樣他們兩條語句在文本上是一模一樣的,他們的HASH值也會一樣,但是由于涉及到查詢的相關(guān)表不一樣,他們事實上是無法共享的。假如這時候用戶C又要查詢同樣一條語句,他查詢的表為scott下的公有同義詞,還有就是SCOTT也查詢同樣一張自己的表emp,情況會是如何呢?
    SQL> connect a/a
    Connected.
    SQL> create table emp ( x int );
    Table created.
    SQL> select * from emp;
    no rows selected
    SQL> connect b/b
    Connected.
    SQL> create table emp ( x int );
    Table created.
    SQL> select * from emp;
    no rows selected
    SQL> conn scott/tiger
    Connected.
    SQL> select * from emp;
    SQL> conn c/c
    Connected.
    SQL> select * from emp;
    SQL> conn/as sysdba
    Connected.
    SQL> select address,hash_value, executions, sql_text
    from v$sql
    where upper(sql_text) like 'SELECT * FROM EMP%'
    /
    ADDRESS  HASH_VALUE EXECUTIONS SQL_TEXT
    -------- ---------- ---------- ------------------------
    78B89E9C 3011704998          1 select * from emp
    78B89E9C 3011704998          1 select * from emp
    78B89E9C 3011704998          2 select * from emp
    ...
      我們可以看到這四個查詢的語句文本和HASH值都是一樣的,但是由于查詢的對象不同,只有后面兩個語句是可以共享的,不同情況的語句還是需要硬解析的。因此在檢查共享池共同SQL語句的時候,是需要根據(jù)具體情況而定的。
      我們可以進一步查詢v$sql_shared_cursor以得知SQL為何不能共享的原因:
    SQL> select kglhdpar, address,
    auth_check_mismatch, translation_mismatch
    from v$sql_shared_cursor
    where kglhdpar in
    ( select address
    from v$sql
    where upper(sql_text) like 'SELECT * FROM EMP%' )
    /
    KGLHDPAR ADDRESS  A T
    -------- -------- - -
    78B89E9C 786C9D78 N N
    78B89E9C 786AC810 Y Y
    78B89E9C 786A11A4 Y Y
    ...
      TRANSLATION_MISMATCH表示SQL游標涉及到的數(shù)據(jù)對象是不同的;AUTH_CHECK_MISMATCH表示對同樣一條SQL語句轉(zhuǎn)換是不匹配的。
      (2、)驗證SQL語句執(zhí)行環(huán)境是否相同。比如同樣一條SQL語句,一個查詢會話加了/*+ first_rows */的HINT,另外一個用戶加/*+ all_rows */的HINT,他們就會產(chǎn)生不同的執(zhí)行計劃,盡管他們是查詢同樣的數(shù)據(jù)。我們下面就一個實例來說明SQL執(zhí)行環(huán)境對解析的影響,我們通過將會話的workarea_size_policy變更來查看對同樣一條SQL語句執(zhí)行的影響:
    SQL> alter system flush shared_pool;
    System altered.
    SQL> show parameter workarea_size_policy
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- --------------
    workarea_size_policy                 string      AUTO
    SQL> select count(*) from t;
    COUNT(*)
    ----------
    5736
    SQL> alter session set workarea_size_policy=manual;
    Session altered.
    SQL> select count(*) from t;
    COUNT(*)
    ----------
    5736
    SQL> select sql_text, child_number, hash_value, address
    from v$sql
    where upper(sql_text) = 'SELECT COUNT(*) FROM T'
    /
    SQL_TEXT                       CHILD_NUMBER HASH_VALUE ADDRESS
    ------------------------------ ------------ ---------- --------
    select count(*) from t                    0 2199322426 78717328
    select count(*) from t                    1 2199322426 78717328
    ...
      可以看到由于不同會話workarea_size_policy設置得不同,即使是同樣一條SQL語句還是無法共享的。通過進一步查詢v$sql_shared_cursor我們可以發(fā)現(xiàn)兩個會話的優(yōu)化器環(huán)境是不同的:
    SQL>selectoptimizer_mismatch
    fromv$sql_shared_cursor
    wherekglhdparin
    (selectaddress
    fromv$sql
    whereupper(sql_text)='SELECTCOUNT(*)FROMT');
    O
    -
    N
    Y
    ...
      通過如上三個步驟檢查以后,如果SQL語句是一致的,那么就會重用原有SQL語句的執(zhí)行計劃和優(yōu)化方案,也就是我們通常所說的軟解析。如果SQL語句沒有找到同樣的副本,那么就需要進行硬解析了。
      4、Oracle根據(jù)提交的SQL語句再查詢相應的數(shù)據(jù)對象是否有統(tǒng)計信息。如果有統(tǒng)計信息的話,那么CBO將會使用這些統(tǒng)計信息產(chǎn)生所有可能的執(zhí)行計劃(可能多達成千上萬個)和相應的Cost,最終選擇Cost最低的那個執(zhí)行計劃。如果查詢的數(shù)據(jù)對象無統(tǒng)計信息,則按RBO的默認規(guī)則選擇相應的執(zhí)行計劃。這個步驟也是解析中最耗費資源的,因此我們應該極力避免硬解析的產(chǎn)生。至此,解析的步驟已經(jīng)全部完成,Oracle將會根據(jù)解析產(chǎn)生的執(zhí)行計劃執(zhí)行SQL語句和提取相應的數(shù)據(jù)。

    posted @ 2014-07-15 10:31 順其自然EVO 閱讀(221) | 評論 (0)編輯 收藏

    與加密后的Access數(shù)據(jù)庫建立連接

      Default.aspx
    <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head id="Head1" runat="server">
    <title>與加密后的Access數(shù)據(jù)庫建立連接</title>
    </head>
    <body>
    <form id="form1" runat="server">
    <div>
    <div>
    <table style="width: 587px; height: 338px">
    <tr>
    <td colspan="6">
    <asp:Image ID="Image1" runat="server" ImageUrl="~/image/head.gif" /></td>
    </tr>
    <tr>
    <td style="width: 100px; height: 13px">
    <asp:Label ID="Label1" runat="server" Font-Size="Smaller" Text="輸入連接Access數(shù)據(jù)庫的密碼:"
    Width="199px"></asp:Label></td>
    <td style="width: 77px; height: 13px">
    <asp:TextBox ID="TxtMm" runat="server" TextMode="Password"></asp:TextBox></td>
    <td style="width: 77px; height: 13px">
    <asp:Button ID="BtnOK" runat="server" OnClick="BtnOK_Click" Text="顯示數(shù)據(jù)" Width="58px" /></td>
    <td style="width: 100px; height: 13px">
    <asp:Label ID="lblMessage" runat="server" Font-Bold="True" Font-Size="Smaller" ForeColor="Red"
    Width="296px"></asp:Label></td>
    <td style="width: 100px; height: 13px">
    </td>
    <td style="width: 95px; height: 13px">
    </td>
    </tr>
    <tr>
    <td colspan="6" style="height: 142px">
    <asp:GridView ID="GridbookSell" runat="server" AutoGenerateColumns="False" CellPadding="4"
    Font-Size="Smaller" ForeColor="#333333" GridLines="None" Width="788px">
    <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
    <Columns>
    <asp:BoundField DataField="圖書編號" HeaderText="圖書編號" />
    <asp:BoundField DataField="圖書名稱" HeaderText="圖書名稱" />
    <asp:BoundField DataField="價格" HeaderText="價格" />
    <asp:BoundField DataField="出版時間" HeaderText="出版時間" />
    <asp:BoundField DataField="類別" HeaderText="類別" />
    <asp:BoundField DataField="備注" HeaderText="備注" />
    </Columns>
    <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
    <EditRowStyle BackColor="#999999" />
    <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
    <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
    <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
    <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
    </asp:GridView>
    </td>
    </tr>
    <tr>
    <td colspan="6" style="height: 60px">
    <asp:Image ID="Image2" runat="server" ImageUrl="~/image/foot.gif" /></td>
    </tr>
    </table>
    </div>
    </div>
    </form>
    </body>
    </html>
      Default.aspx.cs
    using System;
    using System.Configuration;
    using System.Data;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;
    using System.Data.OleDb;
    public partial class _Default : System.Web.UI.Page
    {
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    protected void BtnOK_Click(object sender, EventArgs e)
    {
    string ConStr = "Provider=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:DataBase Password=" + this.TxtMm.Text + ";User Id=admin;Data source=" + Server.MapPath("db_ADO.mdb");
    OleDbConnection Con = new OleDbConnection(ConStr);
    if (this.TxtMm.Text == "")
    {
    Response.Write("<script language=javascript>alert('對不起!文本框不能為空!');location='javascript:history.go(-1)'</script>");
    }
    else
    {
    try
    {
    //打開數(shù)據(jù)庫連接
    Con.Open();
    OleDbDataAdapter Dap = new OleDbDataAdapter("select * from tb_booksell", Con);
    DataSet ds = new DataSet();
    Dap.Fill(ds, "tb_booksell");
    GridbookSell.DataSource = ds;
    GridbookSell.DataBind();
    this.lblMessage.Text = " 恭喜你,與加密后的Access數(shù)據(jù)庫連接成功!";
    }
    catch (Exception error)
    {
    this.lblMessage.Text = " 很遺憾,密碼錯誤,請重新輸入密碼!";
    return;
    }
    finally
    {
    //關(guān)閉數(shù)據(jù)庫連接
    Con.Close();
    }
    }
    }
    }

    posted @ 2014-07-15 10:30 順其自然EVO 閱讀(180) | 評論 (0)編輯 收藏

    僅列出標題
    共394頁: First 上一頁 83 84 85 86 87 88 89 90 91 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統(tǒng)計

    • 隨筆 - 3936
    • 文章 - 404
    • 評論 - 179
    • 引用 - 0

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 99精品全国免费观看视频| 亚洲一级免费毛片| 99热在线免费播放| 日本三级2019在线观看免费| 女人18毛片特级一级免费视频| 国产性生交xxxxx免费| 亚洲一级Av无码毛片久久精品| 亚洲爆乳无码专区| 亚洲嫩草影院在线观看| 亚洲精品无码成人| 国产精品福利在线观看免费不卡| 国产成人精品一区二区三区免费| 黄色片在线免费观看| www亚洲一级视频com| 亚洲av女电影网| 亚洲精品无码高潮喷水A片软| 国产精品视频全国免费观看| 免费能直接在线观看黄的视频| 国产精品色午夜免费视频| 亚洲伊人久久精品影院| 亚洲成a人片在线观看中文!!!| 青青青亚洲精品国产| 国产羞羞的视频在线观看免费| 国产又黄又爽又猛免费app| 免费永久看黄在线观看app| 亚洲线精品一区二区三区| 亚洲性69影院在线观看| 成在线人直播免费视频| 91青青青国产在观免费影视| 拔擦拔擦8x华人免费久久| 亚洲AV永久无码精品成人| 亚洲中文字幕无码mv| 伊人免费在线观看| 免费理论片51人人看电影| 亚洲AV乱码一区二区三区林ゆな | 亚洲人成人无码网www国产| 亚洲视屏在线观看| 久青草国产免费观看| www.黄色免费网站| 亚洲乱码精品久久久久..| 国产精品亚洲lv粉色|