大胆亚洲人体视频,午夜亚洲www湿好大,亚洲欧美黑人猛交群http://www.tkk7.com/sway/彪悍的人生不需要解釋,彪悍的代碼不需要測試。zh-cnSun, 11 May 2025 17:51:20 GMTSun, 11 May 2025 17:51:20 GMT60spring2.5基于事務的單元測試http://www.tkk7.com/sway/archive/2009/06/05/280224.htmlKevin.ZhongKevin.ZhongFri, 05 Jun 2009 07:56:00 GMThttp://www.tkk7.com/sway/archive/2009/06/05/280224.htmlhttp://www.tkk7.com/sway/comments/280224.htmlhttp://www.tkk7.com/sway/archive/2009/06/05/280224.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/280224.htmlhttp://www.tkk7.com/sway/services/trackbacks/280224.html 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration(locations = {"/applicationContext.xml",
 3         "/com/jl/sinter/service/spring/conf/quality_spring_dao.xml",
 4         "/com/jl/sinter/service/spring/conf/quality_spring_service.xml",
 5         "/com/jl/sinter/service/spring/conf/common_spring.xml"
 6 })
 7 @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)   
 8 @Transactional
 9 
10 public class ConsumeFacadeTest {
11 
12 @Test
13     public void getConsumeInfoByFilter() {
14         MonitorQueryFilter filter = new MonitorQueryFilter();
15         filter.setQueryDate("2009-02-16");
16         filter.setDutyClassId("3");
17         filter.setDutyShiftId("2");
18         filter.setSinterId("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx001");
19         List<PowerConsumption> pcList = consumeFacade.getConsumeInfoByFilter(filter);
20         if (CollectionUtils.isNotEmpty(pcList)) {
21             for (PowerConsumption pc : pcList) {
22                 System.out.println(pc);
23             }
24         }
25     }
26 
27 }

Kevin.Zhong 2009-06-05 15:56 發表評論
]]>
MyEclipse快捷鍵全http://www.tkk7.com/sway/archive/2009/01/09/250643.htmlKevin.ZhongKevin.ZhongFri, 09 Jan 2009 03:44:00 GMThttp://www.tkk7.com/sway/archive/2009/01/09/250643.htmlhttp://www.tkk7.com/sway/comments/250643.htmlhttp://www.tkk7.com/sway/archive/2009/01/09/250643.html#Feedback8http://www.tkk7.com/sway/comments/commentRss/250643.htmlhttp://www.tkk7.com/sway/services/trackbacks/250643.html閱讀全文

Kevin.Zhong 2009-01-09 11:44 發表評論
]]>
java對象序列化所引起的循環引用的思考http://www.tkk7.com/sway/archive/2009/01/05/249867.htmlKevin.ZhongKevin.ZhongMon, 05 Jan 2009 03:17:00 GMThttp://www.tkk7.com/sway/archive/2009/01/05/249867.htmlhttp://www.tkk7.com/sway/comments/249867.htmlhttp://www.tkk7.com/sway/archive/2009/01/05/249867.html#Feedback4http://www.tkk7.com/sway/comments/commentRss/249867.htmlhttp://www.tkk7.com/sway/services/trackbacks/249867.html閱讀全文

Kevin.Zhong 2009-01-05 11:17 發表評論
]]>
深入淺出REST[轉載]http://www.tkk7.com/sway/archive/2008/12/09/245155.htmlKevin.ZhongKevin.ZhongTue, 09 Dec 2008 02:04:00 GMThttp://www.tkk7.com/sway/archive/2008/12/09/245155.htmlhttp://www.tkk7.com/sway/comments/245155.htmlhttp://www.tkk7.com/sway/archive/2008/12/09/245155.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/245155.htmlhttp://www.tkk7.com/sway/services/trackbacks/245155.html 深入淺出REST[轉載]

作者 Stefan Tilkov譯者 苑永凱 發布于 2007年12月25日 下午10時10分

不知你是否意識到,圍繞著什么才是實現異構的應用到應用通信的“正確”方式,一場爭論正進行的如火如荼:雖然當前主流的方式明顯地集中在基于 SOAP、WSDL和WS-*規范的Web Services領域,但也有少數人用細小但洪亮的聲音主張說更好的方式是REST,表述性狀態轉移(REpresentational State Transfer)的簡稱。在本文中,我不會涉及爭論的話題,而是嘗試對REST和RESTful HTTP應用集成做實用性的介紹。以我的經驗,有些話題一旦觸及就會引來眾多的討論,當涉及到這方面話題的時候,我會深入詳細地闡述。

REST關鍵原則

大部分對REST的介紹是以其正式的定義和背景作為開場的。但這兒且先按下不表,我先提出一個簡單扼要的定義:REST定義了應該如何正確地使用 (這和大多數人的實際使用方式有很大不同)Web標準,例如HTTP和URI。如果你在設計應用程序時能堅持REST原則,那就預示著你將會得到一個使用 了優質Web架構(這將讓你受益)的系統。總之,五條關鍵原則列舉如下:

  • 為所有“事物”定義ID
  • 將所有事物鏈接在一起
  • 使用標準方法
  • 資源多重表述
  • 無狀態通信

下面讓我們進一步審視這些原則。

為所有“事物”定義ID

在這里我使用了“事物”來代替更正式準確的術語“資源”,因為一條如此簡單的原則,不應該被淹沒在術語當中。思考一下人們構建的系統,通常會找到一 系列值得被標識的關鍵抽象。每個事物都應該是可標識的,都應該擁有一個明顯的ID——在Web中,代表ID的統一概念是:URI。URI構成了一個全局命 名空間,使用URI標識你的關鍵資源意味著它們獲得了一個唯一、全局的ID。

對事物使用一致的命名規則(naming scheme)最主要的好處就是你不需要提出自己的規則——而是依靠某個已被定義,在全球范圍中幾乎完美運行,并且能被絕大多數人所理解的規則。想一下你 構建的上一個應用(假設它不是采用RESTful方式構建的)中的任意一個高級對象(high-level object),那就很有可能看到許多從使用唯一標識中受益的用例。比如,如果你的應用中包含一個對顧客的抽象,那么我可以相當肯定,用戶會希望將一個指 向某個顧客的鏈接,能通過電子郵件發送到同事那里,或者加入到瀏覽器的書簽中,甚至寫到紙上。更透徹地講:如果在一個類似于Amazon.com的在線商 城中,沒有用唯一的ID(一個URI)標識它的每一件商品,可想而知這將是多么可怕的業務決策。

當面對這個原則時,許多人驚訝于這是否意味著需要直接向外界暴露數據庫記錄(或者數據庫記錄ID)——自從多年以來面向對象的實踐告誡我們,要將持 久化的信息作為實現細節隱藏起來之后,哪怕是剛有點想法都常會使人驚恐。但是這條原則與隱藏實現細節兩者之間并沒有任何沖突:通常,值得被URI標識的事 物——資源——要比數據庫記錄抽象的多。例如,一個定單資源可以由定單項、地址以及許多其它方面(可能不希望作為單獨標識的資源暴露出來)組成。標識所有 值得標識的事物,領會這個觀念可以進一步引導你創造出在傳統的應用程序設計中不常見的資源:一個流程或者流程步驟、一次銷售、一次談判、一份報價請求—— 這都是應該被標識的事物的示例。同樣,這也會導致創建比非RESTful設計更多的持久化實體。

下面是一些你可能想到的URI的例子:

http://example.com/customers/1234

http://example.com/orders/2007/10/776654

http://example.com/products/4554

http://example.com/processes/salary-increase-234

正如我選擇了創建便于閱讀的URI——這是個有用的觀點,盡管不是RESTful設計所必須的——應該能十分容易地推測出URI的含義:它們明顯地標識著單一“數據項”。但是再往下看:

http://example.com/orders/2007/11

http://example.com/products?color=green

首先,這兩個URI看起來與之前的稍有不同——畢竟,它們不是對一件事物的標識,而是對一類事物集合的標識(假定第一個URI標識了所有在2007年11月份提交的定單,第二個則是綠顏色產品的集合)。但是這些集合自身也是事物(資源),也應該被標識。

注意,使用唯一、全局統一的命名規則的好處,既適用于瀏覽器中的Web應用,也適用于機對機(machine-to-machine,m2m)通信。

來對第一個原則做下總結:使用URI標識所有值得標識的事物,特別是應用中提供的所有“高級”資源,無論這些資源代表單一數據項、數據項集合、虛擬亦或實際的對象還是計算結果等。

將所有事物鏈接在一起

接下來要討論的原則有一個有點令人害怕的正式描述:“超媒體被當作應用狀態引擎(Hypermedia as the engine of application state)”,有時簡寫為HATEOAS。(嚴格地說,這不是我說的。)這個描述的核心是超媒體概念,換句話說:是鏈接的思想。鏈接是我們在HTML中常見的概念,但是它的用處絕不局限于此(用于人們網絡瀏覽)。考慮一下下面這個虛構的XML片段:

<order self="http://example.com/customers/1234"> 

 <amount>23</amount>

 <product ref="http://example.com/products/4554">

  <customer ref="http://example.com/customers/1234">

  </customer>

 </product>

</order>

如果你觀察文檔中product和customer的鏈接,就可以很容易地想象到,應用程序(已經檢索過文檔)如何“跟隨”鏈接檢索更多的信息。當然,如果使用一個遵守專用命名規范的簡單“id”屬性作為鏈接, 也是可行的——但是僅限于應用環境之內。使用URI表示鏈接的優雅之處在于,鏈接可以指向由不同應用、不同服務器甚至位于另一個大陸上的不同公司提供的資源——因為URI命名規范是全球標準,構成Web的所有資源都可以互聯互通。

超媒體原則還有一個更重要的方面——應用“狀態”。簡而言之,實際上服務器端(如果你愿意,也可以叫服務提供者)為客戶端(服務消費者)提供一組鏈 接,使客戶端能通過鏈接將應用從一個狀態改變為另一個狀態。稍后我們會在另一篇文章中探究這個方面的影響;目前,只需要記住:鏈接是構成動態應用的非常有 效的方式。

對此原則總結如下:任何可能的情況下,使用鏈接指引可以被標識的事物(資源)。也正是超鏈接造就了現在的Web。

使用標準方法

在前兩個原則的討論中暗含著一個假設:接收URI的應用程序可以通過URI明確地一些有意義的事情。如果你在公共汽車上看到一個URI,你可以將它輸入瀏覽器的地址欄中并回車——但是你的瀏覽器如何知道需要對這個URI做些什么呢?

它知道如何去處理URI的原因在于所有的資源都支持同樣的接口,一套同樣的方法(只要你樂意,也可以稱為操作)集合。在HTTP中這被叫做動詞 (verb),除了兩個大家熟知的(GET和POST)之外,標準方法集合中還包含PUT、DELETE、HEAD和OPTIONS。這些方法的含義連同 行為許諾都一起定義在HTTP規范之中。如果你是一名OO開發人員,就可以想象到RESTful HTTP方案中的所有資源都繼承自類似于這樣的一個類(采用類Java、C#的偽語法描述,請注意關鍵的方法):

class Resource {

Resource(URI u);

Response get();

Response post(Request r);

Response put(Request r);

Response delete();

}

由于所有資源使用了同樣的接口,你可以依此使用GET方法檢索一個表述(representation)——也 就是對資源的描述。因為規范中定義了GET的語義,所以可以肯定當你調用它的時候不需要對后果負責——這就是為什么可以“安全”地調用此方法。GET方法 支持非常高效、成熟的緩存,所以在很多情況下,你甚至不需要向服務器發送請求。還可以肯定的是,GET方法具有冪等性[譯 注:指多個相同請求返回相同的結果]——如果你發送了一個GET請求沒有得到結果,你可能不知道原因是請求未能到達目的地,還是響應在反饋的途中丟失了。 冪等性保證了你可以簡單地再發送一次請求解決問題。冪等性同樣適用于PUT(基本的含義是“更新資源數據,如果資源不存在的話,則根據此URI創建一個新 的資源”)和DELETE(你完全可以一遍又一遍地操作它,直到得出結論——刪除不存在的東西沒有任何問題)方法。POST方法,通常表示“創建一個新資 源”,也能被用于調用任意過程,因而它既不安全也不具有冪等性。

如果你采用RESTful的方式暴露應用功能(如果你樂意,也可以稱為服務功能),那這條原則和它的約束同樣也適用于你。如果你已經習慣于另外的設計方式,則很難去接受這條原則——畢竟,你很可能認為你的應用包含了超出這些操作表達范圍的邏輯。請允許我花費一些時間來讓你相信不存在這樣的情況。

來看下面這個簡單的采購方案例子:

Sample Scenario

可以看到,例子中定義了兩個服務程序(沒有包含任何實現細節)。這些服務程序的接口都是為了完成任務(正是我們討論的 OrderManagement和CustomerManagement服務)而定制的。如果客戶端程序試圖使用這些服務,那它必須針對這些特定接口進行 編碼——不可能在這些接口定義之前,使用客戶程序去有目的地和接口協作。這些接口定義了服務程序的應用協議(application protocol)。

在RESTful HTTP方式中,你將通過組成HTTP應用協議的通用接口訪問服務程序。你可能會想出像這樣的方式:

Sample Scenario, done RESTfully

可以看到,服務程序中的特定操作被映射成為標準的HTTP方法——為了消除歧義,我創建了一組全新的資源。“這是騙人的把戲”,我聽見你叫嚷著。 不,這不是欺騙。標識一個顧客的URI上的GET方法正好相當于getCustomerDetails操作。有人用三角形形象化地說明了這一點:

Knobs one can turn

把三個頂點想象為你可以調節的按鈕。可以看到在第一種方法中,你擁有許多操作,許多種類的數據以及固定數量的“實例”(本質上和你擁有的服務程序數 量一致)。在第二種方法中,你擁有固定數量的操作,許多種類的數據和許多調用固定方法的對象。它的意義在于,證明了通過這兩種方式,你基本上可以表示任何 你喜歡的事情。

為什么使用標準方法如此重要?從根本上說,它使你的應用成為Web的一部分——應用程序為Web變成Internet上最成功的應用所做的貢獻,與 它添加到Web中的資源數量成比例。采用RESTful方式,一個應用可能會向Web中添加數以百萬計的客戶URI;如果采用CORBA技術并維持應用的 原有設計方式,那它的貢獻大抵只是一個“端點(endpoint)”——就好比一個非常小的門,僅僅允許有鑰匙的人進入其中的資源域。

統一接口也使得所有理解HTTP應用協議的組件能與你的應用交互。通用客戶程序(generic client)就是從中受益的組件的例子,例如curl、wget、代理、緩存、HTTP服務器、網關還有Google、Yahoo!、MSN等等。

總結如下:為使客戶端程序能與你的資源相互協作,資源應該正確地實現默認的應用協議(HTTP),也就是使用標準的GET、PUT、POST和DELETE方法。

資源多重表述

到目前為止我們一直忽略了一個稍微復雜的問題:客戶程序如何知道該怎樣處理檢索到的數據,比如作為GET或者POST請求的結果?原因是,HTTP 采取的方式是允許數據處理和操作調用之間關系分離的。換句話說,如果客戶程序知道如何處理一種特定的數據格式,那就可以與所有提供這種表述格式的資源交 互。讓我們再用一個例子來闡明這個觀點。利用HTTP內容協商(content negotiation),客戶程序可以請求一種特定格式的表述:

GET /customers/1234 HTTP/1.1

Host: example.com

Accept: application/vnd.mycompany.customer+xml

請求的結果可能是一些由公司專有的XML格式表述的客戶信息。假設客戶程序發送另外一個不同的請求,就如下面這樣:

GET /customers/1234 HTTP/1.1

Host: example.com

Accept: text/x-vcard

結果則可能是VCard格式的客戶地址。(在這里我沒有展示響應的內容,在其HTTP Content-type頭中應該包含著關于數據類型的元數據。)這說明為什么理想的情況下,資源表述應該采用標準格式——如果客戶程序對HTTP應用協 議和一組數據格式都有所“了解”,那么它就可以用一種有意義的方式與世界上任意一個RESTful HTTP應用交互。 不幸的是,我們不可能拿到所有東西的標準格式,但是,或許我們可以想到在公司或者一些合作伙伴中使用標準格式來營造一個小環境。當然以上情況不僅適用于從 服務器端到客戶端的數據,反之既然——倘若從客戶端傳來的數據符合應用協議,那么服務器端就可以使用特定的格式處理數據,而不去關心客戶端的類型。

在實踐中,資源多重表述還有著其它重要的好處:如果你為你的資源提供HTML和XML兩種表述方式,那這些資源不僅可以被你的應用所用,還可以被任意標準Web瀏覽器所用——也就是說,你的應用信息可以被所有會使用Web的人獲取到。

資源多重表述還有另外一種使用方式:你可以將應用的Web UI納入到Web API中——畢竟,API的設計通常是由UI可以提供的功能驅動的,而UI也是通過API執行動作的。將這兩個任務合二為一帶來了令人驚訝的好處,這使得 使用者和調用程序都能得到更好的Web接口。

總結:針對不同的需求提供資源多重表述。

無狀態通信

無狀態通信是我要講到的最后一個原則。首先,需要著重強調的是,雖然REST包含無狀態性(statelessness)的觀念,但這并不是說暴露功能的應用不能有狀態——
事實上,在大部分情況下這會導致整個做法沒有任何用處。REST要求狀態要么被放入資源狀態中,要么保存在客戶端上。或者換句話說,服務器端不能保持除了 單次請求之外的,任何與其通信的客戶端的通信狀態。這樣做的最直接的理由就是可伸縮性—— 如果服務器需要保持客戶端狀態,那么大量的客戶端交互會嚴重影響服務器的內存可用空間(footprint)。(注意,要做到無狀態通信往往需要需要一些 重新設計——不能簡單地將一些session狀態綁縛在URI上,然后就宣稱這個應用是RESTful。)

但除此以外,其它方面可能顯得更為重要:無狀態約束使服務器的變化對客戶端是不可見的,因為在兩次連續的請求中,客戶端并不依賴于同一臺服務器。一 個客戶端從某臺服務器上收到一份包含鏈接的文檔,當它要做一些處理時,這臺服務器宕掉了,可能是硬盤壞掉而被拿去修理,可能是軟件需要升級重啟——如果這 個客戶端訪問了從這臺服務器接收的鏈接,它不會察覺到后臺的服務器已經改變了。

理論上的REST

我承認:以上我所說的REST不是真正的REST,而且我可能有點過多地熱衷于簡單化。但因為我想有一個與眾不同的開場,所以沒有在一開始就介紹其正式的定義和背景。現在就讓我們稍微簡要地介紹一下這方面的內容。

首先,先前我并沒有明確地區分HTTP、RESTful HTTP和REST。要理解這些不同方面之間的關系,我們要先來看看REST的歷史。

Roy T. Fielding在他的博士學位論文(實際上你應該訪問這個鏈接——至少對于一篇學術論文來說,它是相當易讀的。此論文已被翻譯成中文) 中定義了術語REST。Roy曾是許多基本Web協議的主要設計者,其中包括HTTP和URIs,并且他在論文中對這些協議提出了很多想法。(這篇論文被 譽為“REST圣經”,這是恰當的——畢竟,是作者發明了這個術語,所以在定義上,他寫的任何內容都被認為是權威的。)在論文中,Roy首先定義一種方法 論來談論架構風格——高級、抽象的模式,來表達架構方法背后的核心理念。每一個架構風格由一系列的約束(constraints)定義形成。架構風格的例子包括“沒有風格”(根本沒有任何約束)、管道和過濾器(pipe and filter)、客戶端/服務器、分布式對象以及——你猜到它了——REST。

如果對你來說這些聽起來都太抽象了,那就對了——REST在本質上是一個可以被許多不同技術實現的高層次的風格,而且可以被實例化——通過為它的抽 象特性賦上不同的值。比如,REST中包含資源和統一接口的概念——也就是說,所有資源都應該對這些相同的方法作出反應。但是REST并沒有說明是哪些方 法,或者有多少方法。

REST風格的一個“化身”便是HTTP(以及一套相關的一套標準,比如URI),或者稍微抽象一些:Web架構自身。接著上面的例子,HTTP使 用HTTP動詞作為REST統一接口的“實例”。由于Fielding是在Web已經(或者至少是大部分)“完善”了之后才定義的REST風格,有人可能 會爭論兩者是不是100%的匹配。但是無論如何,整體上來說Web、HTTP和URI僅僅是REST風格的一個主要實現。不過,由于Roy Fielding即是REST論文的作者,又對Web架構設計有過深遠的影響,兩者相似也在情理之中。

最后,我在前面一次又一次地使用著術語“RESTful HTTP”,原因很簡單:許多使用HTTP的應用因為一些理由并沒有遵循REST原則,有人會說使用HTTP而不遵循REST原則就等同于濫用HTTP。 當然這聽起來有點狂熱——事實上違反REST約束的原因通常是,僅僅因為每個約束帶來的設計權衡可能不適合于一些特殊情況。但通常,違背REST約束的原 因可歸咎于對其好處認知的缺乏。來看一個明顯的反面案例:使用HTTP GET調用類似于刪除對象的操作,這違反了REST的安全約束和一般性常識(客戶程序不應為此負責,服務器端開發人員大概不是有意而為之)。但在隨后的文 章中,我會提及更多這樣或那樣的對HTTP的濫用。

總結

本文試圖對REST(Web架構)背后的概念提供快速的介紹。RESTful HTTP暴露功能的方式與RPC、分布式對象以及Web Services是不相同的;要真正理解這些不同是需要一些心態的轉變。不管你構建的應用是僅僅想暴露Web UI還是想把API變成Web的一份子,了解下REST的原則還是有好處的。

Stefan Tilkov是InfoQ SOA社區的首席編輯,并且是位于德國和瑞士的innoQ公司的共同創始人、首席顧問和REST狂熱分子首領。

查看英文原文A Brief Introduction to REST

Kevin.Zhong 2008-12-09 10:04 發表評論
]]>
HTTP的狀態碼http://www.tkk7.com/sway/archive/2008/12/08/245042.htmlKevin.ZhongKevin.ZhongMon, 08 Dec 2008 07:51:00 GMThttp://www.tkk7.com/sway/archive/2008/12/08/245042.htmlhttp://www.tkk7.com/sway/comments/245042.htmlhttp://www.tkk7.com/sway/archive/2008/12/08/245042.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/245042.htmlhttp://www.tkk7.com/sway/services/trackbacks/245042.html 完整的 HTTP 1.1規范說明書來自于RFC 2616,你可以在http://www.rfc-editor.org/在線查閱。HTTP 1.1的狀態碼被標記為新特性,因為許多瀏覽器只支持 HTTP 1.0。你應只把狀態碼發送給支持 HTTP 1.1的客戶端,支持協議版本可以通過調用request.getRequestProtocol來檢查。

本部分余下的內容會詳細地介紹 HTTP 1.1中的狀態碼。這些狀態碼被分為五大類:

100-199 用于指定客戶端應相應的某些動作。
200-299 用于表示請求成功。
300-399 用于已經移動的文件并且常被包含在定位頭信息中指定新的地址信息。
400-499 用于指出客戶端的錯誤。
500-599 用于支持服務器錯誤。

HttpServletResponse 中的常量代表關聯不同標準消息的狀態碼。在servlet程序中,你會更多地用到這些常量的標識來使用狀態碼。例如:你一般會使用 response.setStatus(response.SC_NO_CONTENT)而不是 response.setStatus(204),因為后者不易理解而且容易導致錯誤。但是,你應當注意到服務器允許對消息輕微的改變,而客戶端只注意狀 態碼的數字值。所以服務器可能只返回 HTTP/1.1 200 而不是 HTTP/1.1 200 OK。

100 (Continue/繼續)
如 果服務器收到頭信息中帶有100-continue的請求,這是指客戶端詢問是否可以在后續的請求中發送附件。在這種情況下,服務器用 100(SC_CONTINUE)允許客戶端繼續或用417 (Expectation Failed)告訴客戶端不同意接受附件。這個狀態碼是 HTTP 1.1中新加入的。

101 (Switching Protocols/轉換協議)
101 (SC_SWITCHING_PROTOCOLS)狀態碼是指服務器將按照其上的頭信息變為一個不同的協議。這是 HTTP 1.1中新加入的。

200 (OK/正常)
200 (SC_OK)的意思是一切正常。一般用于相應GET和POST請求。這個狀態碼對servlet是缺省的;如果沒有調用setStatus方法的話,就會得到200。

201 (Created/已創建)
201 (SC_CREATED)表示服務器在請求的響應中建立了新文檔;應在定位頭信息中給出它的URL。

202 (Accepted/接受)
202 (SC_ACCEPTED)告訴客戶端請求正在被執行,但還沒有處理完。

203 (Non-Authoritative Information/非官方信息)
狀態碼203 (SC_NON_AUTHORITATIVE_INFORMATION)是表示文檔被正常的返回,但是由于正在使用的是文檔副本所以某些響應頭信息可能不正確。這是 HTTP 1.1中新加入的。

204 (No Content/無內容)
在并沒有新文檔的情況下,204 (SC_NO_CONTENT)確保瀏覽器繼續顯示先前的文檔。這各狀態碼對于用戶周期性的重載某一頁非常有用,并且你可以確定先前的頁面是否已經更新。例如,某個servlet可能作如下操作:
int pageVersion =Integer.parseInt(request.getParameter("pageVersion"));
if (pageVersion >;= currentVersion) {
   response.setStatus(response.SC_NO_CONTENT);
} else {
       // Create regular page
}
但 是,這種方法對通過刷新響應頭信息或等價的HTML標記自動重載的頁面起作用,因為它會返回一個204狀態碼停止以后的重載。但基于JavaScript 腳本的自動重載在這種情況下仍然需要能夠起作用。可以閱讀本書7.2 ( HTTP 1.1 Response Headers and Their Meaning/HTTP 1.1響應頭信息以及他們的意義)部分的詳細討論。

205 (Reset Content/重置內容)
重置內容205 (SC_RESET_CONTENT)的意思是雖然沒有新文檔但瀏覽器要重置文檔顯示。這個狀態碼用于強迫瀏覽器清除表單域。這是 HTTP 1.1中新加入的。

206 (Partial Content/局部內容)
206 (SC_PARTIAL_CONTENT)是在服務器完成了一個包含Range頭信息的局部請求時被發送的。這是 HTTP 1.1中新加入的。

300 (Multiple Choices/多重選擇)
300 (SC_MULTIPLE_CHOICES)表示被請求的文檔可以在多個地方找到,并將在返回的文檔中列出來。如果服務器有首選設置,首選項將會被列于定位響應頭信息中。

301 (Moved Permanently)
301 (SC_MOVED_PERMANENTLY)狀態是指所請求的文檔在別的地方;文檔新的URL會在定位響應頭信息中給出。瀏覽器會自動連接到新的URL。

302 (Found/找到)
與 301有些類似,只是定位頭信息中所給的URL應被理解為臨時交換地址而不是永久的。注意:在 HTTP 1.0中,消息是臨時移動(Moved Temporarily)的而不是被找到,因此HttpServletResponse中的常量是SC_MOVED_TEMPORARILY不是我們以為 的SC_FOUND。

注意
代表狀態碼302的常量是SC_MOVED_TEMPORARILY而不是SC_FOUND。

狀 態碼302是非常有用的因為瀏覽器自動連接在定為響應頭信息中給出的新URL。這非常有用,而且為此有一個專門的方法——sendRedirect。使用 response.sendRedirect(url)比調用 response.setStatus(response.SC_MOVED_TEMPORARILY)和 response.setHeader("Location", url)多幾個好處。首先,response.sendRedirect(url)方法明顯要簡單和容易。第二,servlet自動建立一頁保存這一連接 以提供給那些不能自動轉向的瀏覽器顯示。最后,在servlet 2.2版本(J2EE中的版本)中,sendRedirect能夠處理相對路徑,自動轉換為絕對路徑。但是你只能在2.1版本中使用絕對路徑。

如 果你將用戶轉向到站點的另一頁中,你要用 HttpServletResponse 中的 encodeURL 方法傳送URL。這么做可預防不斷使用基于URL重寫的會話跟蹤的情況。URL重寫是一種在你的網站跟蹤不使用 cookies 的用戶的方法。這是通過在每一個URL尾部附加路徑信息實現的,但是 servlet 會話跟蹤API會自動的注意這些細節。會話跟蹤在第九章討論,并且養成使用 encodeURL 的習慣會使以后添加會話跟蹤的功能更容易很多。

核心技巧
如 果你將用戶轉向到你的站點的其他頁面,用 response.sendRedirect(response.encodeURL(url)) 的方式事先計劃好會話跟蹤(session tracking)要比只是調用 response.sendRedirect(url) 好的多。

這 個狀態碼有時可以與301交換使用。例如,如果你錯誤的訪問了http://host/~user(路徑信息不完整),有些服務器就會回復301狀態碼而 有些則回復302。從技術上說,如果最初的請求是GET瀏覽器只是被假定自動轉向。如果想了解更多細節,請看狀態碼307的討論。

303 (See Other/參見其他信息)
這個狀態碼和 301、302 相似,只是如果最初的請求是 POST,那么新文檔(在定位頭信息中給出)藥用 GET 找回。這個狀態碼是新加入 HTTP 1.1中的。

304 (Not Modified/為修正)
當 客戶端有一個緩存的文檔,通過提供一個 If-Modified-Since 頭信息可指出客戶端只希望文檔在指定日期之后有所修改時才會重載此文檔,用這種方式可以進行有條件的請求。304 (SC_NOT_MODIFIED)是指緩沖的版本已經被更新并且客戶端應刷新文檔。另外,服務器將返回請求的文檔及狀態碼 200。servlet一般情況下不會直接設置這個狀態碼。它們會實現getLastModified方法并根據修正日期讓默認服務方法處理有條件的請 求。這個方法的例程已在2.8部分(An Example Using Servlet Initialization and Page Modification Dates/一個使用servlet初始化和頁面修正日期的例子)給出。

305 (Use Proxy/使用代理)
305 (SC_USE_PROXY)表示所請求的文檔要通過定位頭信息中的代理服務器獲得。這個狀態碼是新加入 HTTP 1.1中的。

307 (Temporary Redirect/臨時重定向)
瀏 覽器處理307狀態的規則與302相同。307狀態被加入到 HTTP 1.1中是由于許多瀏覽器在收到302響應時即使是原始消息為POST的情況下仍然執行了錯誤的轉向。只有在收到303響應時才假定瀏覽器會在POST請 求時重定向。添加這個新的狀態碼的目的很明確:在響應為303時按照GET和POST請求轉向;而在307響應時則按照GET請求轉向而不是POST請 求。注意:由于某些原因在HttpServletResponse中還沒有與這個狀態對應的常量。該狀態碼是新加入HTTP 1.1中的。

注意
在 HttpServletResponse 中沒有 SC_TEMPORARY_REDIRECT 常量,所以你只能顯示的使用307狀態碼。

400 (Bad Request/錯誤請求)
400 (SC_BAD_REQUEST)指出客戶端請求中的語法錯誤。

401 (Unauthorized/未授權)
401 (SC_UNAUTHORIZED)表示客戶端在授權頭信息中沒有有效的身份信息時訪問受到密碼保護的頁面。這個響應必須包含一個WWW- Authenticate的授權信息頭。例如,在本書4.5部分中的“Restricting Access to Web Pages./限制訪問Web頁。”

403 (Forbidden/禁止)
403 (SC_FORBIDDEN)的意思是除非擁有授權否則服務器拒絕提供所請求的資源。這個狀態經常會由于服務器上的損壞文件或目錄許可而引起。

404 (Not Found/未找到)
404 (SC_NOT_FOUND)狀態每個網絡程序員可能都遇到過,他告訴客戶端所給的地址無法找到任何資源。它是表示“沒有所訪問頁面”的標準方式。這個狀 態碼是常用的響應并且在HttpServletResponse類中有專門的方法實現它:sendError("message")。相對于 setStatus使用sendError得好處是:服務器會自動生成一個錯誤頁來顯示錯誤信息。但是,Internet Explorer 5瀏覽器卻默認忽略你發揮的錯誤頁面并顯示其自定義的錯誤提示頁面,雖然微軟這么做違反了 HTTP 規范。要關閉此功能,在工具菜單里,選擇Internet選項,進入高級標簽頁,并確認“顯示友好的 HTTP 錯誤信息”選項(在我的瀏覽器中是倒數第8各選項)沒有被選。但是很少有用戶知道此選項,因此這個特性被IE5隱藏了起來使用戶無法看到你所返回給用戶的 信息。而其他主流瀏覽器及IE4都完全的顯示服務器生成的錯誤提示頁面。可以參考圖6-3及6-4中的例子。

核心警告
默認情況下,IE5忽略服務端生成的錯誤提示頁面。

405 (Method Not Allowed/方法未允許)
405 (SC_METHOD_NOT_ALLOWED)指出請求方法(GET, POST, HEAD, PUT, DELETE, 等)對某些特定的資源不允許使用。該狀態碼是新加入 HTTP 1.1中的。

406 (Not Acceptable/無法訪問)
406 (SC_NOT_ACCEPTABLE)表示請求資源的MIME類型與客戶端中Accept頭信息中指定的類型不一致。見本書7.2部分中的表 7.1(HTTP 1.1 Response Headers and Their Meaning/HTTP 1.1響應頭信息以及他們的意義)中對MIME類型的介紹。406是新加入 HTTP 1.1中的。

407 (Proxy Authentication Required/代理服務器認證要求)
407 (SC_PROXY_AUTHENTICATION_REQUIRED)與401狀態有些相似,只是這個狀態用于代理服務器。該狀態指出客戶端必須通過代 理服務器的認證。代理服務器返回一個Proxy-Authenticate響應頭信息給客戶端,這會引起客戶端使用帶有Proxy- Authorization請求的頭信息重新連接。該狀態碼是新加入 HTTP 1.1中的。

408 (Request Timeout/請求超時)
408 (SC_REQUEST_TIMEOUT)是指服務端等待客戶端發送請求的時間過長。該狀態碼是新加入 HTTP 1.1中的。

409 (Conflict/沖突)
該狀態通常與PUT請求一同使用,409 (SC_CONFLICT)狀態常被用于試圖上傳版本不正確的文件時。該狀態碼是新加入 HTTP 1.1中的。

410 (Gone/已經不存在)
410 (SC_GONE)告訴客戶端所請求的文檔已經不存在并且沒有更新的地址。410狀態不同于404,410是在指導文檔已被移走的情況下使用,而404則用于未知原因的無法訪問。該狀態碼是新加入 HTTP 1.1中的。

411 (Length Required/需要數據長度)
411 (SC_LENGTH_REQUIRED)表示服務器不能處理請求(假設為帶有附件的POST請求),除非客戶端發送Content-Length頭信息指出發送給服務器的數據的大小。該狀態是新加入 HTTP 1.1的。

412 (Precondition Failed/先決條件錯誤)
412 (SC_PRECONDITION_FAILED)狀態指出請求頭信息中的某些先決條件是錯誤的。該狀態是新加入 HTTP 1.1的。

413 (Request Entity Too Large/請求實體過大)
413 (SC_REQUEST_ENTITY_TOO_LARGE)告訴客戶端現在所請求的文檔比服務器現在想要處理的要大。如果服務器認為能夠過一段時間處理,則會包含一個Retry-After的響應頭信息。該狀態是新加入 HTTP 1.1的。

414 (Request URI Too Long/請求URI過長)
414 (SC_REQUEST_URI_TOO_LONG)狀態用于在URI過長的情況時。這里所指的“URI”是指URL中主機、域名及端口號之后的內容。例 如:在URL--http://www.y2k-disaster.com:8080/we/look/silly/now/中URI是指/we /look/silly/now/。該狀態是新加入 HTTP 1.1的。

415 (Unsupported Media Type/不支持的媒體格式)
415 (SC_UNSUPPORTED_MEDIA_TYPE)意味著請求所帶的附件的格式類型服務器不知道如何處理。該狀態是新加入 HTTP 1.1的。

416 (Requested Range Not Satisfiable/請求范圍無法滿足)
416表示客戶端包含了一個服務器無法滿足的Range頭信息的請求。該狀態是新加入 HTTP 1.1的。奇怪的是,在servlet 2.1版本API的HttpServletResponse中并沒有相應的常量代表該狀態。

注意
在servlet 2.1的規范中,類HttpServletResponse并沒有SC_REQUESTED_RANGE_NOT_SATISFIABLE 這樣的常量,所以你只能直接使用416。在servlet 2.2版本之后都包含了此常量。

417 (Expectation Failed/期望失敗)
如 果服務器得到一個帶有100-continue值的Expect請求頭信息,這是指客戶端正在詢問是否可以在后面的請求中發送附件。在這種情況下,服務器 也會用該狀態(417)告訴瀏覽器服務器不接收該附件或用100 (SC_CONTINUE)狀態告訴客戶端可以繼續發送附件。該狀態是新加入 HTTP 1.1的。

500 (Internal Server Error/內部服務器錯誤)
500 (SC_INTERNAL_SERVER_ERROR) 是常用的“服務器錯誤”狀態。該狀態經常由CGI程序引起也可能(但愿不會如此!)由無法正常運行的或返回頭信息格式不正確的servlet引起。

501 (Not Implemented/未實現)
501 (SC_NOT_IMPLEMENTED)狀態告訴客戶端服務器不支持請求中要求的功能。例如,客戶端執行了如PUT這樣的服務器并不支持的命令。

502 (Bad Gateway/錯誤的網關)
502 (SC_BAD_GATEWAY)被用于充當代理或網關的服務器;該狀態指出接收服務器接收到遠端服務器的錯誤響應。

503 (Service Unavailable/服務無法獲得)
狀 態碼503 (SC_SERVICE_UNAVAILABLE)表示服務器由于在維護或已經超載而無法響應。例如,如果某些線程或數據庫連接池已經沒有空閑則 servlet會返回這個頭信息。服務器可提供一個Retry-After頭信息告訴客戶端什么時候可以在試一次。

504 (Gateway Timeout/網關超時)
該狀態也用于充當代理或網關的服務器;它指出接收服務器沒有從遠端服務器得到及時的響應。該狀態是新加入 HTTP 1.1的。

505 (HTTP Version Not Supported/不支持的 HTTP 版本)
505 (SC_HTTP_VERSION_NOT_SUPPORTED)狀態碼是說服務器并不支持在請求中所標明 HTTP 版本。該狀態是新加入 HTTP 1.1的。


Kevin.Zhong 2008-12-08 15:51 發表評論
]]>
checkstyle常用的輸出結果解釋http://www.tkk7.com/sway/archive/2008/11/06/238983.htmlKevin.ZhongKevin.ZhongThu, 06 Nov 2008 03:27:00 GMThttp://www.tkk7.com/sway/archive/2008/11/06/238983.htmlhttp://www.tkk7.com/sway/comments/238983.htmlhttp://www.tkk7.com/sway/archive/2008/11/06/238983.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/238983.htmlhttp://www.tkk7.com/sway/services/trackbacks/238983.html 2“{” should be on the previous line “{” 應該位于前一行
3Methos is missing a javadoc comment方法前面缺少javadoc注釋
4Expected @throws tag for “Exception”在注釋中希望有@throws的說明
5“.” Is preceeded with whitespace “.” 前面不能有空格
6“.” Is followed by whitespace“.” 后面不能有空格
7“=” is not preceeded with whitespace“=” 前面缺少空格
8“=” is not followed with whitespace“=” 后面缺少空格
9“}” should be on the same line“}” 應該與下條語句位于同一行
10Unused @param tag for “unused”沒有參數“unused”,不需注釋
11Variable “CA” missing javadoc變量“CA”缺少javadoc注釋
12Line longer than 80characters行長度超過80
13Line contains a tab character行含有”tab” 字符
14Redundant “Public” modifier冗余的“public” modifier
15Final modifier out of order with the JSL suggestionFinal modifier的順序錯誤
16Avoid using the “.*” form of importImport格式避免使用“.*”
17Redundant import from the same package從同一個包中Import內容
18Unused import-java.util.listImport進來的java.util.list沒有被使用
19Duplicate import to line 13重復Import同一個內容
20Import from illegal package從非法包中 Import內容
21“while” construct must use “{}”“while” 語句缺少“{}”
22Variable “sTest1” must be private and have accessor method變量“sTest1”應該是private的,并且有調用它的方法
23Variable “ABC” must match pattern “^[a-z][a-zA-Z0-9]*$”變量“ABC”不符合命名規則“^[a-z][a-zA-Z0-9]*$”
24“(” is followed by whitespace“(” 后面不能有空格 25“)” is proceeded by whitespace“)” 前面不能有空格

Kevin.Zhong 2008-11-06 11:27 發表評論
]]>
hibernate二級緩存攻略(javaeye)http://www.tkk7.com/sway/archive/2008/11/05/238864.htmlKevin.ZhongKevin.ZhongWed, 05 Nov 2008 09:59:00 GMThttp://www.tkk7.com/sway/archive/2008/11/05/238864.htmlhttp://www.tkk7.com/sway/comments/238864.htmlhttp://www.tkk7.com/sway/archive/2008/11/05/238864.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/238864.htmlhttp://www.tkk7.com/sway/services/trackbacks/238864.html 我的經驗主要來自hibernate2.1版本,基本原理和3.0、3.1是一樣的,請原諒我的頑固不化。

hibernate的session提供了一級緩存,每個session,對同一個id進行兩次load,不會發送兩條sql給數據庫,但是session關閉的時候,一級緩存就失效了。

二級緩存是SessionFactory級別的全局緩存,它底下可以使用不同的緩存類庫,比如ehcache、oscache等,需要設置hibernate.cache.provider_class,我們這里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查詢緩存,加上
hibernate.cache.use_query_cache=true


緩存可以簡單的看成一個Map,通過key在緩存里面找value。

Class的緩存
對于一條記錄,也就是一個PO來說,是根據ID來找的,緩存的key就是ID,value是POJO。無論list,load還是 iterate,只要讀出一個對象,都會填充緩存。但是list不會使用緩存,而iterate會先取數據庫select id出來,然后一個id一個id的load,如果在緩存里面有,就從緩存取,沒有的話就去數據庫load。假設是讀寫緩存,需要設置:
&lt;cache usage="read-write"/&gt;
如果你使用的二級緩存實現是ehcache的話,需要配置ehcache.xml
&lt;cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" /&gt;
其中eternal表示緩存是不是永遠不超時,timeToLiveSeconds是緩存中每個元素(這里也就是一個POJO)的超時時間,如 果eternal="false",超過指定的時間,這個元素就被移走了。timeToIdleSeconds是發呆時間,是可選的。當往緩存里面put 的元素超過500個時,如果overflowToDisk="true",就會把緩存中的部分數據保存在硬盤上的臨時文件里面。
每個需要緩存的class都要這樣配置。如果你沒有配置,hibernate會在啟動的時候警告你,然后使用defaultCache的配置,這樣多個class會共享一個配置。
當某個ID通過hibernate修改時,hibernate會知道,于是移除緩存。
這樣大家可能會想,同樣的查詢條件,第一次先list,第二次再iterate,就可以使用到緩存了。實際上這是很難的,因為你無法判斷什么時候 是第一次,而且每次查詢的條件通常是不一樣的,假如數據庫里面有100條記錄,id從1到100,第一次list的時候出了前50個id,第二次 iterate的時候卻查詢到30至70號id,那么30-50是從緩存里面取的,51到70是從數據庫取的,共發送1+20條sql。所以我一直認為 iterate沒有什么用,總是會有1+N的問題。
(題外話:有說法說大型查詢用list會把整個結果集裝入內存,很慢,而iterate只select id比較好,但是大型查詢總是要分頁查的,誰也不會真的把整個結果集裝進來,假如一頁20條的話,iterate共需要執行21條語句,list雖然選擇 若干字段,比iterate第一條select id語句慢一些,但只有一條語句,不裝入整個結果集hibernate還會根據數據庫方言做優化,比如使用mysql的limit,整體看來應該還是 list快。)
如果想要對list或者iterate查詢的結果緩存,就要用到查詢緩存了

查詢緩存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
&lt;cache name="net.sf.hibernate.cache.StandardQueryCache"
   maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
   timeToLiveSeconds="7200" overflowToDisk="true"/&gt;
&lt;cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
   maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/&gt;
然后
query.setCacheable(true);//激活查詢緩存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可選
第二行指定要使用的cacheRegion是myCacheRegion,即你可以給每個查詢緩存做一個單獨的配置,使用setCacheRegion來做這個指定,需要在ehcache.xml里面配置它:
&lt;cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" /&gt;
如果省略第二行,不設置cacheRegion的話,那么會使用上面提到的標準查詢緩存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

對于查詢緩存來說,緩存的key是根據hql生成的sql,再加上參數,分頁等信息(可以通過日志輸出看到,不過它的輸出不是很可讀,最好改一下它的代碼)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
參數是"tiger%",那么查詢緩存的key*大約*是這樣的字符串(我是憑記憶寫的,并不精確,不過看了也該明白了):
select * from cat c where c.name like ? , parameter:tiger%
這樣,保證了同樣的查詢、同樣的參數等條件下具有一樣的key。
現在說說緩存的value,如果是list方式的話,value在這里并不是整個結果集,而是查詢出來的這一串ID。也就是說,不管是list方 法還是iterate方法,第一次查詢的時候,它們的查詢方式很它們平時的方式是一樣的,list執行一條sql,iterate執行1+N條,多出來的 行為是它們填充了緩存。但是到同樣條件第二次查詢的時候,就都和iterate的行為一樣了,根據緩存的key去緩存里面查到了value,value是 一串id,然后在到class的緩存里面去一個一個的load出來。這樣做是為了節約內存。
可以看出來,查詢緩存需要打開相關類的class緩存。list和iterate方法第一次執行的時候,都是既填充查詢緩存又填充class緩存的。
這里還有一個很容易被忽視的重要問題,即打開查詢緩存以后,即使是list方法也可能遇到1+N的問題!相同 條件第一次list的時候,因為查詢緩存中找不到,不管class緩存是否存在數據,總是發送一條sql語句到數據庫獲取全部數據,然后填充查詢緩存和 class緩存。但是第二次執行的時候,問題就來了,如果你的class緩存的超時時間比較短,現在class緩存都超時了,但是查詢緩存還在,那么 list方法在獲取id串以后,將會一個一個去數據庫load!因此,class緩存的超時時間一定不能短于查詢緩存設置的超時時間!如果還設置了發呆時 間的話,保證class緩存的發呆時間也大于查詢的緩存的生存時間。這里還有其他情況,比如class緩存被程序強制evict了,這種情況就請自己注意 了。

另外,如果hql查詢包含select字句,那么查詢緩存里面的value就是整個結果集了。

當hibernate更新數據庫的時候,它怎么知道更新哪些查詢緩存呢?
hibernate在一個地方維護每個表的最后更新時間,其實也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的緩存配置里面。
當通過hibernate更新的時候,hibernate會知道這次更新影響了哪些表。然后它更新這些表的最后更新時間。每個緩存都有一個生成時 間和這個緩存所查詢的表,當hibernate查詢一個緩存是否存在的時候,如果緩存存在,它還要取出緩存的生成時間和這個緩存所查詢的表,然后去查找這 些表的最后更新時間,如果有一個表在生成時間后更新過了,那么這個緩存是無效的。
可以看出,只要更新過一個表,那么凡是涉及到這個表的查詢緩存就失效了,因此查詢緩存的命中率可能會比較低。

Collection緩存
需要在hbm的collection里面設置
&lt;cache usage="read-write"/&gt;
假如class是Cat,collection叫children,那么ehcache里面配置
&lt;cache name="com.xxx.pojo.Cat.children"
   maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
   overflowToDisk="true" /&gt;
Collection的緩存和前面查詢緩存的list一樣,也是只保持一串id,但它不會因為這個表更新過就失效,一個collection緩存僅在這個collection里面的元素有增刪時才失效。
這樣有一個問題,如果你的collection是根據某個字段排序的,當其中一個元素更新了該字段時,導致順序改變時,collection緩存里面的順序沒有做更新。

緩存策略
只讀緩存(read-only):沒有什么好說的
讀/寫緩存(read-write):程序可能要的更新數據
不嚴格的讀/寫緩存(nonstrict-read-write):需要更新數據,但是兩個事務更新同一條記錄的可能性很小,性能比讀寫緩存好
事務緩存(transactional):緩存支持事務,發生異常的時候,緩存也能夠回滾,只支持jta環境,這個我沒有怎么研究過

讀寫緩存和不嚴格讀寫緩存在實現上的區別在于,讀寫緩存更新緩存的時候會把緩存里面的數據換成一個鎖,其他事務如果去取相應的緩存數據,發現被鎖住了,然后就直接取數據庫查詢。
在hibernate2.1的ehcache實現中,如果鎖住部分緩存的事務發生了異常,那么緩存會一直被鎖住,直到60秒后超時。
不嚴格讀寫緩存不鎖定緩存中的數據。


使用二級緩存的前置條件
你的hibernate程序對數據庫有獨占的寫訪問權,其他的進程更新了數據庫,hibernate是不可能知道的。你操作數據庫必需直接通過 hibernate,如果你調用存儲過程,或者自己使用jdbc更新數據庫,hibernate也是不知道的。hibernate3.0的大批量更新和刪 除是不更新二級緩存的,但是據說3.1已經解決了這個問題。
這個限制相當的棘手,有時候hibernate做批量更新、刪除很慢,但是你卻不能自己寫jdbc來優化,很郁悶吧。
SessionFactory也提供了移除緩存的方法,你一定要自己寫一些JDBC的話,可以調用這些方法移除緩存,這些方法是:
void evict(Class persistentClass)
          Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
          Evict an entry from the second-level cache.
void evictCollection(String roleName)
          Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
          Evict an entry from the second-level cache.
void evictQueries()
          Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
          Evict any query result sets cached in the named query cache region.
不過我不建議這樣做,因為這樣很難維護。比如你現在用JDBC批量更新了某個表,有3個查詢緩存會用到這個表,用 evictQueries(String cacheRegion)移除了3個查詢緩存,然后用evict(Class persistentClass)移除了class緩存,看上去好像完整了。不過哪天你添加了一個相關查詢緩存,可能會忘記更新這里的移除代碼。如果你的 jdbc代碼到處都是,在你添加一個查詢緩存的時候,還知道其他什么地方也要做相應的改動嗎?

----------------------------------------------------

總結:
不要想當然的以為緩存一定能提高性能,僅僅在你能夠駕馭它并且條件合適的情況下才是這樣的。hibernate的二級緩存限制還是比較多的,不方便用jdbc可能會大大的降低更新性能。在不了解原理的情況下亂用,可能會有1+N的問題。不當的使用還可能導致讀出臟數據。
如果受不了hibernate的諸多限制,那么還是自己在應用程序的層面上做緩存吧。
在越高的層面上做緩存,效果就會越好。就好像盡管磁盤有緩存,數據庫還是要實現自己的緩存,盡管數據庫有緩存,咱們的應用程序還是要做緩存。因為 底層的緩存它并不知道高層要用這些數據干什么,只能做的比較通用,而高層可以有針對性的實現緩存,所以在更高的級別上做緩存,效果也要好些吧。


終于寫完了,好累……

Kevin.Zhong 2008-11-05 17:59 發表評論
]]>
c3p0屬性詳解http://www.tkk7.com/sway/archive/2008/11/05/238860.htmlKevin.ZhongKevin.ZhongWed, 05 Nov 2008 09:29:00 GMThttp://www.tkk7.com/sway/archive/2008/11/05/238860.htmlhttp://www.tkk7.com/sway/comments/238860.htmlhttp://www.tkk7.com/sway/archive/2008/11/05/238860.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/238860.htmlhttp://www.tkk7.com/sway/services/trackbacks/238860.html<c3p0-config>
<default-config>
<!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 -->
<property name="acquireIncrement">3</property>

<!--定義在從數據庫獲取新連接失敗后重復嘗試的次數。Default: 30 -->
<property name="acquireRetryAttempts">30</property>

<!--兩次連接中間隔時間,單位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>

<!--連接關閉時默認將所有未提交的操作回滾。Default: false -->
<property name="autoCommitOnClose">false</property>

<!--c3p0將建一張名為Test的空表,并使用其自帶的查詢語句進行測試。如果定義了這個參數那么
屬性preferredTestQuery將被忽略。你不能在這張Test表上進行任何操作,它將只供c3p0測試
使用。Default: null
-->
<property name="automaticTestTable">Test</property>

<!--獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。但是數據源仍有效
保留,并在下次調用getConnection()的時候繼續嘗試獲取連接。如果設為true,那么在嘗試
獲取連接失敗后該數據源將申明已斷開并永久關閉。Default: false
-->
<property name="breakAfterAcquireFailure">false</property>

<!--當連接池用完時客戶端調用getConnection()后等待獲取新連接的時間,超時后將拋出
SQLException,如設為0則無限期等待。單位毫秒。Default: 0 
-->
<property name="checkoutTimeout">100</property>

<!--通過實現ConnectionTester或QueryConnectionTester的類來測試連接。類名需制定全路徑。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester
-->
<property name="connectionTesterClassName"></property>

<!--指定c3p0 libraries的路徑,如果(通常都是這樣)在本地即可獲得那么無需設置,默認null即可
Default: null
-->
<property name="factoryClassLocation">null</property>

<!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
(文檔原文)作者強烈建議不使用的一個屬性
-->
<property name="forceIgnoreUnresolvedTransactions">false</property>

<!--每60秒檢查所有連接池中的空閑連接。Default: 0 -->
<property name="idleConnectionTestPeriod">60</property>

<!--初始化時獲取三個連接,取值應在minPoolSize與maxPoolSize之間。Default: 3 -->
<property name="initialPoolSize">3</property>

<!--最大空閑時間,60秒內未使用則連接被丟棄。若為0則永不丟棄。Default: 0 -->
<property name="maxIdleTime">60</property>

<!--連接池中保留的最大連接數。Default: 15 -->
<property name="maxPoolSize">15</property>

<!--JDBC的標準參數,用以控制數據源內加載的PreparedStatements數量。但由于預緩存的statements
屬于單個connection而不是整個連接池。所以設置這個參數需要考慮到多方面的因素。
如果maxStatements與maxStatementsPerConnection均為0,則緩存被關閉。Default: 0
-->
<property name="maxStatements">100</property>

<!--maxStatementsPerConnection定義了連接池內單個連接所擁有的最大緩存statements數。Default: 0 -->
<property name="maxStatementsPerConnection"></property>

<!--c3p0是異步操作的,緩慢的JDBC操作通過幫助進程完成。擴展這些操作可以有效的提升性能
通過多線程實現多個操作同時被執行。Default: 3
-->
<property name="numHelperThreads">3</property>

<!--當用戶調用getConnection()時使root用戶成為去獲取連接的用戶。主要用于連接池連接非c3p0
的數據源時。Default: null
-->
<property name="overrideDefaultUser">root</property>

<!--與overrideDefaultUser參數對應使用的一個參數。Default: null-->
<property name="overrideDefaultPassword">password</property>

<!--密碼。Default: null-->
<property name="password"></property>

<!--定義所有連接測試都執行的測試語句。在使用連接測試的情況下這個一顯著提高測試速度。注意:
測試的表必須在初始數據源的時候就存在。Default: null
-->
<property name="preferredTestQuery">select id from test where id=1</property>

<!--用戶修改系統配置參數執行前最多等待300秒。Default: 300 -->
<property name="propertyCycle">300</property>

<!--因性能消耗大請只在需要的時候使用它。如果設為true那么在每個connection提交的
時候都將校驗其有效性。建議使用idleConnectionTestPeriod或automaticTestTable
等方法來提升連接測試的性能。Default: false 
-->
<property name="testConnectionOnCheckout">false</property>

<!--如果設為true那么在取得連接的同時將校驗連接的有效性。Default: false -->
<property name="testConnectionOnCheckin">true</property>

<!--用戶名。Default: null-->
<property name="user">root</property>

<!--早期的c3p0版本對JDBC接口采用動態反射代理。在早期版本用途廣泛的情況下這個參數
允許用戶恢復到動態反射代理以解決不穩定的故障。最新的非反射代理更快并且已經開始
廣泛的被使用,所以這個參數未必有用。現在原先的動態反射與新的非反射代理同時受到
支持,但今后可能的版本可能不支持動態反射代理。Default: false
-->
<property name="usesTraditionalReflectiveProxies">false</property>

<property name="automaticTestTable">con_test</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">25</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">0</property>
<user-overrides user="swaldman">
</user-overrides>
</default-config>
<named-config name="dumbTestConfig">
<property name="maxStatements">200</property>
<user-overrides user="poop">
<property name="maxStatements">300</property>
</user-overrides>
</named-config>
</c3p0-config>


Kevin.Zhong 2008-11-05 17:29 發表評論
]]>
Hibernate 參數設置一覽表 http://www.tkk7.com/sway/archive/2008/11/05/238836.htmlKevin.ZhongKevin.ZhongWed, 05 Nov 2008 08:03:00 GMThttp://www.tkk7.com/sway/archive/2008/11/05/238836.htmlhttp://www.tkk7.com/sway/comments/238836.htmlhttp://www.tkk7.com/sway/archive/2008/11/05/238836.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/238836.htmlhttp://www.tkk7.com/sway/services/trackbacks/238836.html 屬性名 用途 hibernate.dialect 一個Hibernate Dialect類名允許Hibernate針對特定的關系數據庫生成優化的SQL. 取值 full.classname.of.Dialect hibernate.show_sql 輸出所有SQL語句到控制臺. 有一個另外的選擇是把org.hibernate.SQL這個log category設為debug。 eg. true | false hibernate.format_sql 在log和console中打印出更漂亮的SQL。 取值 true | false hibernate.default_schema 在生成的SQL中, 將給定的schema/tablespace附加于非全限定名的表名上. 取值 SCHEMA_NAME hibernate.default_catalog 在生成的SQL中, 將給定的catalog附加于非全限定名的表名上. 取值 CATALOG_NAME hibernate.session_factory_name SessionFactory創建后,將自動使用這個名字綁定到JNDI中. 取值 jndi/composite/name hibernate.max_fetch_depth 為單向關聯(一對一, 多對一)的外連接抓取(outer join fetch)樹設置最大深度. 值為0意味著將關閉默認的外連接抓取. 取值 建議在03之間取值 hibernate.default_batch_fetch_size 為Hibernate關聯的批量抓取設置默認數量. 取值 建議的取值為4, 8, 和16 hibernate.default_entity_mode 為由這個SessionFactory打開的所有Session指定默認的實體表現模式. 取值 dynamic-map, dom4j, pojo hibernate.order_updates 強制Hibernate按照被更新數據的主鍵,為SQL更新排序。這么做將減少在高并發系統中事務的死鎖。 取值 true | false hibernate.generate_statistics 如果開啟, Hibernate將收集有助于性能調節的統計數據. 取值 true | false hibernate.use_identifer_rollback 如果開啟, 在對象被刪除時生成的標識屬性將被重設為默認值. 取值 true | false hibernate.use_sql_comments 如果開啟, Hibernate將在SQL中生成有助于調試的注釋信息, 默認值為false. 取值 true | false

表 3.4.  Hibernate JDBC和連接(connection)屬性

屬性名 用途
hibernate.jdbc.fetch_size 非零值,指定JDBC抓取數量的大小 (調用Statement.setFetchSize()).
hibernate.jdbc.batch_size 非零值,允許Hibernate使用JDBC2的批量更新. 取值 建議取530之間的值
hibernate.jdbc.batch_versioned_data 如果你想讓你的JDBC驅動從executeBatch()返回正確的行計數 , 那么將此屬性設為true(開啟這個選項通常是安全的). 同時,Hibernate將為自動版本化的數據使用批量DML. 默認值為false. eg. true | false
hibernate.jdbc.factory_class 選擇一個自定義的Batcher. 多數應用程序不需要這個配置屬性. eg. classname.of.Batcher
hibernate.jdbc.use_scrollable_resultset 允許Hibernate使用JDBC2的可滾動結果集. 只有在使用用戶提供的JDBC連接時,這個選項才是必要的, 否則Hibernate會使用連接的元數據. 取值 true | false
hibernate.jdbc.use_streams_for_binary 在JDBC讀寫binary (二進制)serializable (可序列化) 的類型時使用流(stream)(系統級屬性). 取值 true | false
hibernate.jdbc.use_get_generated_keys 在數據插入數據庫之后,允許使用JDBC3 PreparedStatement.getGeneratedKeys() 來獲取數據庫生成的key(鍵)。需要JDBC3+驅動和JRE1.4+, 如果你的數據庫驅動在使用Hibernate的標 識生成器時遇到問題,請將此值設為false. 默認情況下將使用連接的元數據來判定驅動的能力. 取值 true|false
hibernate.connection.provider_class 自定義ConnectionProvider的類名, 此類用來向Hibernate提供JDBC連接. 取值 classname.of.ConnectionProvider
hibernate.connection.isolation 設置JDBC事務隔離級別. 查看java.sql.Connection來了解各個值的具體意義, 但請注意多數數據庫都不支持所有的隔離級別. 取值 1, 2, 4, 8
hibernate.connection.autocommit 允許被緩存的JDBC連接開啟自動提交(autocommit) (不建議). 取值 true | false
hibernate.connection.release_mode 指定Hibernate在何時釋放JDBC連接. 默認情況下,直到Session被顯式關閉或被斷開連接時,才會釋放JDBC連接. 對于應用程序服務器的JTA數據源, 你應當使用after_statement, 這樣在每次JDBC調用后,都會主動的釋放連接. 對于非JTA的連接, 使用after_transaction在每個事務結束時釋放連接是合理的. auto將為JTA和CMT事務策略選擇after_statement, 為JDBC事務策略選擇after_transaction. 取值 on_close | after_transaction | after_statement | auto
hibernate.connection.<propertyName> 將JDBC屬性propertyName傳遞到DriverManager.getConnection()中去.
hibernate.jndi.<propertyName> 將屬性propertyName傳遞到JNDI InitialContextFactory中去.

表 3.5.  Hibernate緩存屬性

屬性名 用途
hibernate.cache.provider_class 自定義的CacheProvider的類名. 取值 classname.of.CacheProvider
hibernate.cache.use_minimal_puts 以頻繁的讀操作為代價, 優化二級緩存來最小化寫操作. 在Hibernate3中,這個設置對的集群緩存非常有用, 對集群緩存的實現而言,默認是開啟的. 取值 true|false
hibernate.cache.use_query_cache 允許查詢緩存, 個別查詢仍然需要被設置為可緩存的. 取值 true|false
hibernate.cache.use_second_level_cache 能用來完全禁止使用二級緩存. 對那些在類的映射定義中指定<cache>的類,會默認開啟二級緩存. 取值 true|false
hibernate.cache.query_cache_factory 自定義實現QueryCache接口的類名, 默認為內建的StandardQueryCache. 取值 classname.of.QueryCache
hibernate.cache.region_prefix 二級緩存區域名的前綴. 取值 prefix
hibernate.cache.use_structured_entries 強制Hibernate以更人性化的格式將數據存入二級緩存. 取值 true|false

表 3.6.  Hibernate事務屬性

屬性名 用途
hibernate.transaction.factory_class 一個TransactionFactory的類名, 用于Hibernate Transaction API (默認為JDBCTransactionFactory). 取值 classname.of.TransactionFactory
jta.UserTransaction 一個JNDI名字,被JTATransactionFactory用來從應用服務器獲取JTA UserTransaction. 取值 jndi/composite/name
hibernate.transaction.manager_lookup_class 一個TransactionManagerLookup的類名 - 當使用JVM級緩存,或在JTA環境中使用hilo生成器的時候需要該類. 取值 classname.of.TransactionManagerLookup
hibernate.transaction.flush_before_completion 如果開啟, session在事務完成后將被自動清洗(flush)。 現在更好的方法是使用自動session上下文管理。取值 true | false
hibernate.transaction.auto_close_session 如果開啟, session在事務完成后將被自動關閉。 現在更好的方法是使用自動session上下文管理。取值 true | false

表 3.7.  其他屬性

屬性名 用途
hibernate.current_session_context_class 為"當前" Session指定一個(自定義的)策略。eg. jta | thread | custom.Class
hibernate.query.factory_class 選擇HQL解析器的實現. 取值 org.hibernate.hql.ast.ASTQueryTranslatorFactory or org.hibernate.hql.classic.ClassicQueryTranslatorFactory
hibernate.query.substitutions 將Hibernate查詢中的符號映射到SQL查詢中的符號 (符號可能是函數名或常量名字). 取值 hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC
hibernate.hbm2ddl.auto SessionFactory創建時,自動檢查數據庫結構,或者將數據庫schema的DDL導出到數據庫. 使用 create-drop時,在顯式關閉SessionFactory時,將drop掉數據庫schema. 取值 validate | update | create | create-drop
hibernate.cglib.use_reflection_optimizer 開啟CGLIB來替代運行時反射機制(系統級屬性). 反射機制有時在除錯時比較有用. 注意即使關閉這個優化, Hibernate還是需要CGLIB. 你不能在hibernate.cfg.xml中設置此屬性. 取值 true | false

3.4.1.  SQL方言

你應當總是為你的數據庫將hibernate.dialect屬性設置成正確的 org.hibernate.dialect.Dialect子類. 如果你指定一種方言, Hibernate將為上面列出的一些屬性使用合理的默認值, 為你省去了手工指定它們的功夫.

表 3.8.  Hibernate SQL方言 (hibernate.dialect)

RDBMS 方言
DB2 org.hibernate.dialect.DB2Dialect
DB2 AS/400 org.hibernate.dialect.DB2400Dialect
DB2 OS390 org.hibernate.dialect.DB2390Dialect
PostgreSQL org.hibernate.dialect.PostgreSQLDialect
MySQL org.hibernate.dialect.MySQLDialect
MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect
MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect
Oracle (any version) org.hibernate.dialect.OracleDialect
Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect
Sybase org.hibernate.dialect.SybaseDialect
Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect
Microsoft SQL Server org.hibernate.dialect.SQLServerDialect
SAP DB org.hibernate.dialect.SAPDBDialect
Informix org.hibernate.dialect.InformixDialect
HypersonicSQL org.hibernate.dialect.HSQLDialect
Ingres org.hibernate.dialect.IngresDialect
Progress org.hibernate.dialect.ProgressDialect
Mckoi SQL org.hibernate.dialect.MckoiDialect
Interbase org.hibernate.dialect.InterbaseDialect
Pointbase org.hibernate.dialect.PointbaseDialect
FrontBase org.hibernate.dialect.FrontbaseDialect
Firebird org.hibernate.dialect.FirebirdDialect

表 3.9.  Hibernate日志類別

類別 功能
org.hibernate.SQL 在所有SQL DML語句被執行時為它們記錄日志
org.hibernate.type 為所有JDBC參數記錄日志
org.hibernate.tool.hbm2ddl 在所有SQL DDL語句執行時為它們記錄日志
org.hibernate.pretty 在session清洗(flush)時,為所有與其關聯的實體(最多20個)的狀態記錄日志
org.hibernate.cache 為所有二級緩存的活動記錄日志
org.hibernate.transaction 為事務相關的活動記錄日志
org.hibernate.jdbc 為所有JDBC資源的獲取記錄日志
org.hibernate.hql.AST 在解析查詢的時候,記錄HQL和SQL的AST分析日志
org.hibernate.secure 為JAAS認證請求做日志
org.hibernate 為任何Hibernate相關信息做日志 (信息量較大, 但對查錯非常有幫助)

表 3.10. JTA TransactionManagers

Transaction工廠類 應用程序服務器
org.hibernate.transaction.JBossTransactionManagerLookup JBoss
org.hibernate.transaction.WeblogicTransactionManagerLookup Weblogic
org.hibernate.transaction.WebSphereTransactionManagerLookup WebSphere
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup WebSphere 6
org.hibernate.transaction.OrionTransactionManagerLookup Orion
org.hibernate.transaction.ResinTransactionManagerLookup Resin
org.hibernate.transaction.JOTMTransactionManagerLookup JOTM
org.hibernate.transaction.JOnASTransactionManagerLookup JOnAS
org.hibernate.transaction.JRun4TransactionManagerLookup JRun4
org.hibernate.transaction.BESTransactionManagerLookup Borland ES


Kevin.Zhong 2008-11-05 16:03 發表評論
]]>
利用Ecipse生成Javadoc亂碼解決方法http://www.tkk7.com/sway/archive/2008/11/05/238822.htmlKevin.ZhongKevin.ZhongWed, 05 Nov 2008 06:53:00 GMThttp://www.tkk7.com/sway/archive/2008/11/05/238822.htmlhttp://www.tkk7.com/sway/comments/238822.htmlhttp://www.tkk7.com/sway/archive/2008/11/05/238822.html#Feedback0http://www.tkk7.com/sway/comments/commentRss/238822.htmlhttp://www.tkk7.com/sway/services/trackbacks/238822.html 1)  -encoding charsetName
2) -charset charsetName

第一個參數表示javadoc 程序讀取java源文件時候應該采用什么編碼
第二個參數表示javadoc 程序寫html文件時采用的編碼形式,并會在HTML中加入如下標簽

 網管下載dl.bitscn.com

1 <! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
2 <!-- NewPage -->
3 < HTML >
4 < HEAD >
5 <!--  Generated by javadoc (build 1.5.0) on Thu Feb 01 21:10:10 CST 2007  --> 
6 <!-- -這下面的charset隨編碼的不同而不同,這里面為utf-8編碼-- -->
7 < META  http-equiv ="Content-Type"  content ="text/html; charset=utf-8" >

如果文件格式為UTF8格式的,可以采用如下形式進行Generate Javadoc:
javadoc  -encoding UTF-8 -charset UTF-8 <other params>

Kevin.Zhong 2008-11-05 14:53 發表評論
]]>
主站蜘蛛池模板: 亚洲第一网站免费视频| 免费看男人j放进女人j免费看| 日本免费xxxx| 亚洲精品在线视频观看| xx视频在线永久免费观看| 亚洲国产综合在线| 免费中文熟妇在线影片 | 免费播放春色aⅴ视频| 日韩欧美亚洲中文乱码| 亚洲第一黄色网址| 国产伦精品一区二区免费| 国产亚洲成av片在线观看| 日韩电影免费观看| 亚洲人色大成年网站在线观看| 91在线品视觉盛宴免费| 亚洲精品中文字幕无码A片老| 在线日韩av永久免费观看| 粉色视频成年免费人15次| 亚洲区小说区图片区| 精品国产污污免费网站| 亚洲国产综合人成综合网站00| 大地资源免费更新在线播放| 国产成人亚洲精品播放器下载| 国产亚洲精品不卡在线| 免费国产黄网站在线观看| 亚洲人成电影网站色| 亚洲成人国产精品| 99久久国产免费中文无字幕| 亚洲国产精品精华液| 亚洲最大AV网站在线观看| 4hu四虎最新免费地址| 青青免费在线视频| 亚洲高清免费在线观看| 日本一道本高清免费| a在线观看免费视频| 亚洲日日做天天做日日谢| 4338×亚洲全国最大色成网站| 猫咪免费人成网站在线观看| 色噜噜的亚洲男人的天堂| 亚洲av不卡一区二区三区| 在线观看免费国产视频|