Hibernate 學(xué)習(xí)準(zhǔn)備
Posted on 2005-11-21 18:00 Terry的Blog 閱讀(669) 評(píng)論(0) 編輯 收藏 所屬分類: java語(yǔ)言Hibernate源代碼包簡(jiǎn)要介紹
net.sf.hibernate.*
該包的類基本上都是接口類和異常類
net.sf.hibernate.cache.*
JCS的實(shí)現(xiàn)類
net.sf.hibernate.cfg.*
配置文件讀取類
net.sf.hibernate.collection.*
Hibernate集合接口實(shí)現(xiàn)類,例如List,Set,Bag等等,Hibernate之所以要自行編寫(xiě)集合接口實(shí)現(xiàn)類是為了支持lazy loading
net.sf.hibernate.connection.*
幾個(gè)數(shù)據(jù)庫(kù)連接池的Provider
net.sf.hibernate.dialect.*
支持多種數(shù)據(jù)庫(kù)特性,每個(gè)Dialect實(shí)現(xiàn)類代表一種數(shù)據(jù)庫(kù),描述了該數(shù)據(jù)庫(kù)支持的數(shù)據(jù)類型和其它特點(diǎn),例如是否有AutoIncrement,是否有Sequence,是否有分頁(yè)sql等等
net.sf.hibernate.eg.*
Hibernate文檔中用到的例子
net.sf.hibernate.engine.*
這個(gè)包的類作用比較散
net.sf.hibernate.expression.*
HQL支持的表達(dá)式
net.sf.hibernate.hq.*
HQL實(shí)現(xiàn)
net.sf.hibernate.id.*
ID生成器
net.sf.hibernate.impl.*
最核心的包,一些重要接口的實(shí)現(xiàn)類,如果Session,SessionFactory,Query等
net.sf.hibernate.jca.*
JCA支持,把Session包裝為支持JCA的接口實(shí)現(xiàn)類
net.sf.hibernate.jmx.*
我不懂JMX,只知道JMX是用來(lái)編寫(xiě)App Server的管理程序的,大概是JMX部分接口的實(shí)現(xiàn),使得App Server可以通過(guò)JMX接口管理Hibernate
net.sf.hibernate.loader.*
也是很核心的包,主要是生成sql語(yǔ)句的
net.sf.hibernate.lob.*
Blob和Clob支持
net.sf.hibernate.mapping.*
hbm文件的屬性實(shí)現(xiàn)
net.sf.hibernate.metadata.*
PO的Meta實(shí)現(xiàn)
net.sf.hibernate.odmg.*
ODMG是一個(gè)ORM標(biāo)準(zhǔn),這個(gè)包是ODMG標(biāo)準(zhǔn)的實(shí)現(xiàn)類
net.sf.hibernate.persister.*
核心包,實(shí)現(xiàn)持久對(duì)象和表之間的映射
net.sf.hibernate.proxy.*
Proxy和Lazy Loading支持
net.sf.hibernate.ps.*
該包是PreparedStatment Cache
net.sf.hibernate.sql.*
生成JDBC sql語(yǔ)句的包
net.sf.hibernate.test.*
測(cè)試類,你可以用junit來(lái)測(cè)試Hibernate
net.sf.hibernate.tool.hbm2ddl.*
用hbm配置文件生成DDL
net.sf.hibernate.transaction.*
Hibernate Transaction實(shí)現(xiàn)類
net.sf.hibernate.type.*
Hibernate中定義的持久對(duì)象的屬性的數(shù)據(jù)類型
net.sf.hibernate.util.*
一些工具類,作用比較散
net.sf.hibernate.xml.*
XML數(shù)據(jù)綁定
Hibernate入門(mén) - 基礎(chǔ)配置
在Hibernate的src目錄下有一個(gè)hibernate.properties模板,我們不必自己從頭寫(xiě),修改模板就可以了

java代碼: |
hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N' |
這個(gè)配置意思是當(dāng)你在Hibernate里面輸入true的時(shí)候,Hibernate會(huì)轉(zhuǎn)化為0插入數(shù)據(jù)庫(kù),當(dāng)你在Hibernate里面輸入false的時(shí)候,Hibernate會(huì)轉(zhuǎn)化為1插入數(shù)據(jù)庫(kù),后面的Y,N同理。對(duì)于某些數(shù)據(jù)庫(kù),例如Oracle來(lái)說(shuō),沒(méi)有boolean數(shù)據(jù)類型,就是采用1代表true,0代表false,因此使用這個(gè)配置在Hibernate里面直接用true/false會(huì)非常直觀。
java代碼: |
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.driver_class org.gjt.mm.mysql.Driver hibernate.connection.driver_class com.mysql.jdbc.Driver hibernate.connection.url jdbc:mysql:///test hibernate.connection.username root hibernate.connection.password |
這是一個(gè)連接MySQL數(shù)據(jù)庫(kù)的例子,很直觀,不必解釋,不同的數(shù)據(jù)庫(kù)的連接參數(shù)模板中全部給出了。
java代碼: |
hibernate.connection.pool_size 1 hibernate.statement_cache.size 25 |
這是Hibernate自帶的連接池的配置參數(shù),在默認(rèn)情況下將采用。意義很直觀,不多解釋。只是提醒一點(diǎn),Hibernate這個(gè)連接池是非常原始非常簡(jiǎn)單的連接池,如果你在項(xiàng)目中用Hibernate的話,建議你首選App Server的連接池,次選Hibernate帶的DBCP連接池。自帶的連接池應(yīng)該做為末選。
如果你采用DBCP連接池,除了要配置DBCP連接池以外,還需要取消掉下行的注釋:
java代碼: |
hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider |
其它的連接池同理。
如果采用App Server的連接池,假設(shè)App Server連接池的DataSource的JNDI名稱為"mypool"的話,配置應(yīng)該如下:
java代碼: |
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.datasource mypool hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider |
其它參數(shù)就不必寫(xiě)了,因?yàn)橐呀?jīng)在App Server配置連接池的時(shí)候指定好了。
如果你不是在App Server環(huán)境中使用Hibernate,例如遠(yuǎn)程客戶端程序,但是你又想用App Server的數(shù)據(jù)庫(kù)連接池,那么你還需要配置JNDI的參數(shù),例如Hibernate連接遠(yuǎn)程Weblogic上的數(shù)據(jù)庫(kù)連接池:
java代碼: |
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.datasource mypool hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider hibernate.jndi.class weblogic.jndi.WLInitialContextFactory hibernate.jndi.url t3://servername:7001/ |
最后,如果你需要在EJB或者JTA中使用Hibernate,需要取消下行的注釋:
java代碼: |
hibernate.transaction.factory_class net.sf.hibernate.transaction.JTATransactionFactory |
雜項(xiàng)配置:
java代碼: |
hibernate.show_sql false |
是否將Hibernate發(fā)送給數(shù)據(jù)庫(kù)的sql顯示出來(lái),這是一個(gè)非常非常有用處的功能。當(dāng)你在調(diào)試Hibernate的時(shí)候,讓Hibernate打印sql語(yǔ)句,可以幫助你迅速解決問(wèn)題。
java代碼: |
#hibernate.connection.isolation 4 |
指定數(shù)據(jù)庫(kù)的隔離級(jí)別,往往不同的數(shù)據(jù)庫(kù)有自己定義的隔離級(jí)別,未必是Hibernate的設(shè)置所能更改的,所以也不必去管它了。
java代碼: |
hibernate.jdbc.fetch_size 50 hibernate.jdbc.batch_size 25 |
這兩個(gè)選項(xiàng)非常非常非常重要!!!將嚴(yán)重影響Hibernate的CRUD性能!
java代碼: |
C = create, R = read, U = update, D = delete |
Fetch Size 是設(shè)定JDBC的Statement讀取數(shù)據(jù)的時(shí)候每次從數(shù)據(jù)庫(kù)中取出的記錄條數(shù)。例如一次查詢1萬(wàn)條記錄,對(duì)于Oracle的JDBC驅(qū)動(dòng)來(lái)說(shuō),是不會(huì)1次性把1萬(wàn)條取出來(lái)的,而只會(huì)取出Fetch Size條數(shù),當(dāng)紀(jì)錄集遍歷完了這些記錄以后,再去數(shù)據(jù)庫(kù)取Fetch Size條數(shù)據(jù)。因此大大節(jié)省了無(wú)謂的內(nèi)存消耗。當(dāng)然Fetch Size設(shè)的越大,讀數(shù)據(jù)庫(kù)的次數(shù)越少,速度越快;Fetch Size越小,讀數(shù)據(jù)庫(kù)的次數(shù)越多,速度越慢。這有點(diǎn)像平時(shí)我們寫(xiě)程序?qū)懹脖P(pán)文件一樣,設(shè)立一個(gè)Buffer,每次寫(xiě)入Buffer,等Buffer滿了以后,一次寫(xiě)入硬盤(pán),道理相同。
Oracle數(shù)據(jù)庫(kù)的JDBC驅(qū)動(dòng)默認(rèn)的Fetch Size=10,是一個(gè)非常保守的設(shè)定,根據(jù)我的測(cè)試,當(dāng)Fetch Size=50的時(shí)候,性能會(huì)提升1倍之多,當(dāng)Fetch Size=100,性能還能繼續(xù)提升20%,F(xiàn)etch Size繼續(xù)增大,性能提升的就不顯著了。因此我建議使用Oracle的一定要將Fetch Size設(shè)到50。
不過(guò)并不是所有的數(shù)據(jù)庫(kù)都支持Fetch Size特性,例如MySQL就不支持。MySQL就像我上面說(shuō)的那種最壞的情況,他總是一下就把1萬(wàn)條記錄完全取出來(lái),內(nèi)存消耗會(huì)非常非常驚人!這個(gè)情況就沒(méi)有什么好辦法了

Batch Size是設(shè)定對(duì)數(shù)據(jù)庫(kù)進(jìn)行批量刪除,批量更新和批量插入的時(shí)候的批次大小,有點(diǎn)相當(dāng)于設(shè)置Buffer緩沖區(qū)大小的意思。Batch Size越大,批量操作的向數(shù)據(jù)庫(kù)發(fā)送sql的次數(shù)越少,速度就越快。我做的一個(gè)測(cè)試結(jié)果是當(dāng)Batch Size=0的時(shí)候,使用Hibernate對(duì)Oracle數(shù)據(jù)庫(kù)刪除1萬(wàn)條記錄需要25秒,Batch Size = 50的時(shí)候,刪除僅僅需要5秒!!! 可見(jiàn)有多么大的性能提升!很多人做Hibernate和JDBC的插入性能測(cè)試會(huì)奇怪的發(fā)現(xiàn)Hibernate速度至少是JDBC的兩倍,就是因?yàn)镠ibernate使用了Batch Insert,而他們寫(xiě)的JDBC沒(méi)有使用Batch的緣故。以我的經(jīng)驗(yàn)來(lái)看,Oracle數(shù)據(jù)庫(kù) Batch Size = 30 的時(shí)候比較合適,50也不錯(cuò),性能會(huì)繼續(xù)提升,50以上,性能提升的非常微弱,反而消耗內(nèi)存更加多,就沒(méi)有必要了。
java代碼: |
#hibernate.jdbc.use_scrollable_resultset true |
設(shè)定是否可以使用JDBC2.0規(guī)范的可滾動(dòng)結(jié)果集,這對(duì)Hibernate的分頁(yè)顯示有一定的作用,默認(rèn)就好了。
java代碼: |
#hibernate.cglib.use_reflection_optimizer false |
默認(rèn)打開(kāi),啟用cglib反射優(yōu)化。cglib是用來(lái)在Hibernate中動(dòng)態(tài)生成PO字節(jié)碼的,打開(kāi)優(yōu)化可以加快字節(jié)碼構(gòu)造的速度。
不過(guò),當(dāng)你在調(diào)試程序過(guò)程中,特別是和proxy,lazy loading相關(guān)的應(yīng)用中,代碼出錯(cuò),但是出錯(cuò)提示信息有語(yǔ)焉不詳,那么你可以把cglib優(yōu)化關(guān)掉,這樣Hibernate會(huì)輸出比較詳細(xì)的調(diào)試信息,幫助你debug。
Hibernate的靈活性也是一把雙刃劍,用好了就特別舒服,用不好,就特別頭疼。把我原來(lái)在jdon一個(gè)帖子轉(zhuǎn)過(guò)來(lái),談到了這個(gè)問(wèn)題:
一、Hibernate是JDBC的輕量級(jí)的對(duì)象封裝,它是一個(gè)獨(dú)立的對(duì)象持久層框架,和App Server,和EJB沒(méi)有什么必然的聯(lián)系。Hibernate可以用在任何JDBC可以使用的場(chǎng)合,例如Java應(yīng)用程序的數(shù)據(jù)庫(kù)訪問(wèn)代碼,DAO接口的實(shí)現(xiàn)類,甚至可以是BMP里面的訪問(wèn)數(shù)據(jù)庫(kù)的代碼。從這個(gè)意義上來(lái)說(shuō),Hibernate和EB不是一個(gè)范疇的東西,也不存在非此即彼的關(guān)系。
二、Hibernate是一個(gè)和JDBC密切關(guān)聯(lián)的框架,所以Hibernate的兼容性和JDBC驅(qū)動(dòng),和數(shù)據(jù)庫(kù)都有一定的關(guān)系,但是和使用它的Java程序,和App Server沒(méi)有任何關(guān)系,也不存在兼容性問(wèn)題。
三、Hibernate不能用來(lái)直接和Entity Bean做對(duì)比,只有放在整個(gè)J2EE項(xiàng)目的框架中才能比較。并且即使是放在軟件整體框架中來(lái)看,Hibernate也是做為JDBC的替代者出現(xiàn)的,而不是Entity Bean的替代者出現(xiàn)的,讓我再列一次我已經(jīng)列n次的框架結(jié)構(gòu):
傳統(tǒng)的架構(gòu):
1) Session Bean <-> Entity Bean <-> DB
為了解決性能障礙的替代架構(gòu):
2) Session Bean <-> DAO <-> JDBC <-> DB
使用Hibernate來(lái)提高上面架構(gòu)的開(kāi)發(fā)效率的架構(gòu):
3) Session Bean <-> DAO <-> Hibernate <-> DB
就上面3個(gè)架構(gòu)來(lái)分析:
1、內(nèi)存消耗:采用JDBC的架構(gòu)2無(wú)疑是最省內(nèi)存的,Hibernate的架構(gòu)3次之,EB的架構(gòu)1最差。
2、運(yùn)行效率:如果JDBC的代碼寫(xiě)的非常優(yōu)化,那么JDBC架構(gòu)運(yùn)行效率最高,但是實(shí)際項(xiàng)目中,這一點(diǎn)幾乎做不到,這需要程序員非常精通JDBC,運(yùn)用Batch語(yǔ)句,調(diào)整PreapredStatement的Batch Size和Fetch Size等參數(shù),以及在必要的情況下采用結(jié)果集cache等等。而一般情況下程序員是做不到這一點(diǎn)的。因此Hibernate架構(gòu)表現(xiàn)出最快的運(yùn)行效率。EB的架構(gòu)效率會(huì)差的很遠(yuǎn)。
3、開(kāi)發(fā)效率:在有JBuilder的支持下以及簡(jiǎn)單的項(xiàng)目,EB架構(gòu)開(kāi)發(fā)效率最高,JDBC次之,Hibernate最差。但是在大的項(xiàng)目,特別是持久層關(guān)系映射很復(fù)雜的情況下,Hibernate效率高的驚人,JDBC次之,而EB架構(gòu)很可能會(huì)失敗。
4、分布式,安全檢查,集群,負(fù)載均衡的支持
由于有SB做為Facade,3個(gè)架構(gòu)沒(méi)有區(qū)別。
四、EB和Hibernate學(xué)習(xí)難度在哪里?
EB的難度在哪里?不在復(fù)雜的XML配置文件上,而在于EB運(yùn)用稍微不慎,就有嚴(yán)重的性能障礙。所以難在你需要學(xué)習(xí)很多EJB設(shè)計(jì)模式來(lái)避開(kāi)性能問(wèn)題,需要學(xué)習(xí)App Server和EB的配置來(lái)優(yōu)化EB的運(yùn)行效率。做EB的開(kāi)發(fā)工作,程序員的大部分精力都被放到了EB的性能問(wèn)題上了,反而沒(méi)有更多的精力關(guān)注本身就主要投入精力去考慮的對(duì)象持久層的設(shè)計(jì)上來(lái)。
Hibernate難在哪里?不在Hibernate本身的復(fù)雜,實(shí)際上Hibernate非常的簡(jiǎn)單,難在Hibernate太靈活了。
當(dāng)你用EB來(lái)實(shí)現(xiàn)持久層的時(shí)候,你會(huì)發(fā)現(xiàn)EB實(shí)在是太笨拙了,笨拙到你根本沒(méi)有什么可以選擇的余地,所以你根本就不用花費(fèi)精力去設(shè)計(jì)方案,去平衡方案的好壞,去費(fèi)腦筋考慮選擇哪個(gè)方案,因?yàn)橹挥形ㄒ坏姆桨笖[在你面前,你只能這么做,沒(méi)得選擇。
Hibernate相反,它太靈活了,相同的問(wèn)題,你至少可以設(shè)計(jì)出十幾種方案來(lái)解決,所以特別的犯難,究竟用這個(gè),還是用那個(gè)呢?這些方案之間到底有什么區(qū)別呢?他們的運(yùn)行原理有什么不同?運(yùn)行效率哪個(gè)比較好?光是主鍵生成,就有七八種方案供你選擇,你為難不為難?集合屬性可以用Set,可以用List,還可以用Bag,到底哪個(gè)效率高,你為難不為難?查詢可以用iterator,可以用list,哪個(gè)好,有什么區(qū)別?你為難不為難?復(fù)合主鍵你可以直接在hbm里面配置,也可以自定義CustomerType,哪種比較好些?你為難不為難?對(duì)于一個(gè)表,你可以選擇單一映射一個(gè)對(duì)象,也可以映射成父子對(duì)象,還可以映射成兩個(gè)1:1的對(duì)象,在什么情況下用哪種方案比較好,你為難不為難?
這個(gè)列表可以一直開(kāi)列下去,直到你不想再看下去為止。當(dāng)你面前擺著無(wú)數(shù)的眼花繚亂的方案的時(shí)候,你會(huì)覺(jué)得幸福呢?還是悲哀呢?如果你是一個(gè)負(fù)責(zé)的程序員,那么你一定會(huì)仔細(xì)研究每種方案的區(qū)別,每種方案的效率,每種方案的適用場(chǎng)合,你會(huì)覺(jué)得你已經(jīng)陷入進(jìn)去拔不出來(lái)了。如果是用EB,你第一秒種就已經(jīng)做出了決定,根本沒(méi)得選擇,比如說(shuō)集合屬性,你只能用Collection,如果是Hibernate,你會(huì)在Bag,List和Set之間來(lái)回猶豫不決,甚至搞不清楚的話,程序都沒(méi)有辦法寫(xiě)。