Hibernate源代碼包簡要介紹
net.sf.hibernate.*
該包的類基本上都是接口類和異常類
net.sf.hibernate.cache.*
JCS的實現類
net.sf.hibernate.cfg.*
配置文件讀取類
net.sf.hibernate.collection.*
Hibernate集合接口實現類,例如List,Set,Bag等等,Hibernate之所以要自行編寫集合接口實現類是為了支持lazy loading
net.sf.hibernate.connection.*
幾個數據庫連接池的Provider
net.sf.hibernate.dialect.*
支持多種數據庫特性,每個Dialect實現類代表一種數據庫,描述了該數據庫支持的數據類型和其它特點,例如是否有AutoIncrement,是否有Sequence,是否有分頁sql等等
net.sf.hibernate.eg.*
Hibernate文檔中用到的例子
net.sf.hibernate.engine.*
這個包的類作用比較散
net.sf.hibernate.expression.*
HQL支持的表達式
net.sf.hibernate.hq.*
HQL實現
net.sf.hibernate.id.*
ID生成器
net.sf.hibernate.impl.*
最核心的包,一些重要接口的實現類,如果Session,SessionFactory,Query等
net.sf.hibernate.jca.*
JCA支持,把Session包裝為支持JCA的接口實現類
net.sf.hibernate.jmx.*
我不懂JMX,只知道JMX是用來編寫App Server的管理程序的,大概是JMX部分接口的實現,使得App Server可以通過JMX接口管理Hibernate
net.sf.hibernate.loader.*
也是很核心的包,主要是生成sql語句的
net.sf.hibernate.lob.*
Blob和Clob支持
net.sf.hibernate.mapping.*
hbm文件的屬性實現
net.sf.hibernate.metadata.*
PO的Meta實現
net.sf.hibernate.odmg.*
ODMG是一個ORM標準,這個包是ODMG標準的實現類
net.sf.hibernate.persister.*
核心包,實現持久對象和表之間的映射
net.sf.hibernate.proxy.*
Proxy和Lazy Loading支持
net.sf.hibernate.ps.*
該包是PreparedStatment Cache
net.sf.hibernate.sql.*
生成JDBC sql語句的包
net.sf.hibernate.test.*
測試類,你可以用junit來測試Hibernate
net.sf.hibernate.tool.hbm2ddl.*
用hbm配置文件生成DDL
net.sf.hibernate.transaction.*
Hibernate Transaction實現類
net.sf.hibernate.type.*
Hibernate中定義的持久對象的屬性的數據類型
net.sf.hibernate.util.*
一些工具類,作用比較散
net.sf.hibernate.xml.*
XML數據綁定
Hibernate入門 - 基礎配置
Hibernate配置文件可以有兩種格式,一種是hibernate.properties,另一種是hibernate.cfg.xml。后者稍微方便一些,當增加hbm映射文件的時候,可以直接在hibernate.cfg.xml里面增加,不必像hibernate.properties必須在初始化代碼中加入。但不管怎么說,兩種的配置項都是一樣的,下面詳細介紹:
在Hibernate的src目錄下有一個hibernate.properties模板,我們不必自己從頭寫,修改模板就可以了
java代碼: |
hibernate.query.substitutions true 1, false 0, yes 'Y', no 'N'
|
這個配置意思是當你在Hibernate里面輸入true的時候,Hibernate會轉化為0插入數據庫,當你在Hibernate里面輸入false的時候,Hibernate會轉化為1插入數據庫,后面的Y,N同理。對于某些數據庫,例如Oracle來說,沒有boolean數據類型,就是采用1代表true,0代表false,因此使用這個配置在Hibernate里面直接用true/false會非常直觀。
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
|
這是一個連接MySQL數據庫的例子,很直觀,不必解釋,不同的數據庫的連接參數模板中全部給出了。
java代碼: |
hibernate.connection.pool_size 1 hibernate.statement_cache.size 25
|
這是Hibernate自帶的連接池的配置參數,在默認情況下將采用。意義很直觀,不多解釋。只是提醒一點,Hibernate這個連接池是非常原始非常簡單的連接池,如果你在項目中用Hibernate的話,建議你首選App Server的連接池,次選Hibernate帶的DBCP連接池。自帶的連接池應該做為末選。
如果你采用DBCP連接池,除了要配置DBCP連接池以外,還需要取消掉下行的注釋:
java代碼: |
hibernate.connection.provider_class net.sf.hibernate.connection.DBCPConnectionProvider
|
其它的連接池同理。
如果采用App Server的連接池,假設App Server連接池的DataSource的JNDI名稱為"mypool"的話,配置應該如下:
java代碼: |
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect hibernate.connection.datasource mypool hibernate.connection.provider_class net.sf.hibernate.connection.DatasourceConnectionProvider
|
其它參數就不必寫了,因為已經在App Server配置連接池的時候指定好了。
如果你不是在App Server環境中使用Hibernate,例如遠程客戶端程序,但是你又想用App Server的數據庫連接池,那么你還需要配置JNDI的參數,例如Hibernate連接遠程Weblogic上的數據庫連接池:
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
|
雜項配置:
java代碼: |
hibernate.show_sql false
|
是否將Hibernate發送給數據庫的sql顯示出來,這是一個非常非常有用處的功能。當你在調試Hibernate的時候,讓Hibernate打印sql語句,可以幫助你迅速解決問題。
java代碼: |
#hibernate.connection.isolation 4
|
指定數據庫的隔離級別,往往不同的數據庫有自己定義的隔離級別,未必是Hibernate的設置所能更改的,所以也不必去管它了。
java代碼: |
hibernate.jdbc.fetch_size 50 hibernate.jdbc.batch_size 25
|
這兩個選項非常非常非常重要?。?!將嚴重影響Hibernate的CRUD性能!
java代碼: |
C = create, R = read, U = update, D = delete
|
Fetch Size 是設定JDBC的Statement讀取數據的時候每次從數據庫中取出的記錄條數。例如一次查詢1萬條記錄,對于Oracle的JDBC驅動來說,是不會1次性把1萬條取出來的,而只會取出Fetch Size條數,當紀錄集遍歷完了這些記錄以后,再去數據庫取Fetch Size條數據。因此大大節省了無謂的內存消耗。當然Fetch Size設的越大,讀數據庫的次數越少,速度越快;Fetch Size越小,讀數據庫的次數越多,速度越慢。這有點像平時我們寫程序寫硬盤文件一樣,設立一個Buffer,每次寫入Buffer,等Buffer滿了以后,一次寫入硬盤,道理相同。
Oracle數據庫的JDBC驅動默認的Fetch Size=10,是一個非常保守的設定,根據我的測試,當Fetch Size=50的時候,性能會提升1倍之多,當Fetch Size=100,性能還能繼續提升20%,Fetch Size繼續增大,性能提升的就不顯著了。因此我建議使用Oracle的一定要將Fetch Size設到50。
不過并不是所有的數據庫都支持Fetch Size特性,例如MySQL就不支持。MySQL就像我上面說的那種最壞的情況,他總是一下就把1萬條記錄完全取出來,內存消耗會非常非常驚人!這個情況就沒有什么好辦法了
Batch Size是設定對數據庫進行批量刪除,批量更新和批量插入的時候的批次大小,有點相當于設置Buffer緩沖區大小的意思。Batch Size越大,批量操作的向數據庫發送sql的次數越少,速度就越快。我做的一個測試結果是當Batch Size=0的時候,使用Hibernate對Oracle數據庫刪除1萬條記錄需要25秒,Batch Size = 50的時候,刪除僅僅需要5秒?。。?可見有多么大的性能提升!很多人做Hibernate和JDBC的插入性能測試會奇怪的發現Hibernate速度至少是JDBC的兩倍,就是因為Hibernate使用了Batch Insert,而他們寫的JDBC沒有使用Batch的緣故。以我的經驗來看,Oracle數據庫 Batch Size = 30 的時候比較合適,50也不錯,性能會繼續提升,50以上,性能提升的非常微弱,反而消耗內存更加多,就沒有必要了。
java代碼: |
#hibernate.jdbc.use_scrollable_resultset true
|
設定是否可以使用JDBC2.0規范的可滾動結果集,這對Hibernate的分頁顯示有一定的作用,默認就好了。
java代碼: |
#hibernate.cglib.use_reflection_optimizer false
|
默認打開,啟用cglib反射優化。cglib是用來在Hibernate中動態生成PO字節碼的,打開優化可以加快字節碼構造的速度。
不過,當你在調試程序過程中,特別是和proxy,lazy loading相關的應用中,代碼出錯,但是出錯提示信息有語焉不詳,那么你可以把cglib優化關掉,這樣Hibernate會輸出比較詳細的調試信息,幫助你debug。
Hibernate的靈活性也是一把雙刃劍,用好了就特別舒服,用不好,就特別頭疼。把我原來在jdon一個帖子轉過來,談到了這個問題:
一、Hibernate是JDBC的輕量級的對象封裝,它是一個獨立的對象持久層框架,和App Server,和EJB沒有什么必然的聯系。Hibernate可以用在任何JDBC可以使用的場合,例如Java應用程序的數據庫訪問代碼,DAO接口的實現類,甚至可以是BMP里面的訪問數據庫的代碼。從這個意義上來說,Hibernate和EB不是一個范疇的東西,也不存在非此即彼的關系。
二、Hibernate是一個和JDBC密切關聯的框架,所以Hibernate的兼容性和JDBC驅動,和數據庫都有一定的關系,但是和使用它的Java程序,和App Server沒有任何關系,也不存在兼容性問題。
三、Hibernate不能用來直接和Entity Bean做對比,只有放在整個J2EE項目的框架中才能比較。并且即使是放在軟件整體框架中來看,Hibernate也是做為JDBC的替代者出現的,而不是Entity Bean的替代者出現的,讓我再列一次我已經列n次的框架結構:
傳統的架構:
1) Session Bean <-> Entity Bean <-> DB
為了解決性能障礙的替代架構:
2) Session Bean <-> DAO <-> JDBC <-> DB
使用Hibernate來提高上面架構的開發效率的架構:
3) Session Bean <-> DAO <-> Hibernate <-> DB
就上面3個架構來分析:
1、內存消耗:采用JDBC的架構2無疑是最省內存的,Hibernate的架構3次之,EB的架構1最差。
2、運行效率:如果JDBC的代碼寫的非常優化,那么JDBC架構運行效率最高,但是實際項目中,這一點幾乎做不到,這需要程序員非常精通JDBC,運用Batch語句,調整PreapredStatement的Batch Size和Fetch Size等參數,以及在必要的情況下采用結果集cache等等。而一般情況下程序員是做不到這一點的。因此Hibernate架構表現出最快的運行效率。EB的架構效率會差的很遠。
3、開發效率:在有JBuilder的支持下以及簡單的項目,EB架構開發效率最高,JDBC次之,Hibernate最差。但是在大的項目,特別是持久層關系映射很復雜的情況下,Hibernate效率高的驚人,JDBC次之,而EB架構很可能會失敗。
4、分布式,安全檢查,集群,負載均衡的支持
由于有SB做為Facade,3個架構沒有區別。
四、EB和Hibernate學習難度在哪里?
EB的難度在哪里?不在復雜的XML配置文件上,而在于EB運用稍微不慎,就有嚴重的性能障礙。所以難在你需要學習很多EJB設計模式來避開性能問題,需要學習App Server和EB的配置來優化EB的運行效率。做EB的開發工作,程序員的大部分精力都被放到了EB的性能問題上了,反而沒有更多的精力關注本身就主要投入精力去考慮的對象持久層的設計上來。
Hibernate難在哪里?不在Hibernate本身的復雜,實際上Hibernate非常的簡單,難在Hibernate太靈活了。
當你用EB來實現持久層的時候,你會發現EB實在是太笨拙了,笨拙到你根本沒有什么可以選擇的余地,所以你根本就不用花費精力去設計方案,去平衡方案的好壞,去費腦筋考慮選擇哪個方案,因為只有唯一的方案擺在你面前,你只能這么做,沒得選擇。
Hibernate相反,它太靈活了,相同的問題,你至少可以設計出十幾種方案來解決,所以特別的犯難,究竟用這個,還是用那個呢?這些方案之間到底有什么區別呢?他們的運行原理有什么不同?運行效率哪個比較好?光是主鍵生成,就有七八種方案供你選擇,你為難不為難?集合屬性可以用Set,可以用List,還可以用Bag,到底哪個效率高,你為難不為難?查詢可以用iterator,可以用list,哪個好,有什么區別?你為難不為難?復合主鍵你可以直接在hbm里面配置,也可以自定義CustomerType,哪種比較好些?你為難不為難?對于一個表,你可以選擇單一映射一個對象,也可以映射成父子對象,還可以映射成兩個1:1的對象,在什么情況下用哪種方案比較好,你為難不為難?
這個列表可以一直開列下去,直到你不想再看下去為止。當你面前擺著無數的眼花繚亂的方案的時候,你會覺得幸福呢?還是悲哀呢?如果你是一個負責的程序員,那么你一定會仔細研究每種方案的區別,每種方案的效率,每種方案的適用場合,你會覺得你已經陷入進去拔不出來了。如果是用EB,你第一秒種就已經做出了決定,根本沒得選擇,比如說集合屬性,你只能用Collection,如果是Hibernate,你會在Bag,List和Set之間來回猶豫不決,甚至搞不清楚的話,程序都沒有辦法寫。