-- hbm.xml 與 Annotations 性能比較
任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載請保留以下作者信息和鏈接:
作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
關(guān)鍵字:Hibernate Validator
我在前面一篇文章<Hibernate Annotations 實(shí)戰(zhàn)-- 從 hbm.xml 到 Annotations>:
中,有很多開發(fā)者在談?wù)撝刑岬?有沒有必要從 hbm.xml 往 Annotations 上轉(zhuǎn)移. 那么在這篇文章中我們就來討論一下 hbm.xml 與 Annotations的優(yōu)缺點(diǎn),看看那種情況最適合你.
首先,討論一下 xml 配置文件的優(yōu)點(diǎn), 個人認(rèn)為主要優(yōu)點(diǎn)就是當(dāng)你改變底層配置時 不需要改變和重新編譯代碼,只需要在xml 中更改就可以了,例如 Hibernate.cfg.xml 當(dāng)你要更改底層數(shù)據(jù)庫時, 只要更改配置文件就可以了.Hibernate會為你做好別的事情.
那么xml的缺點(diǎn)呢,個人認(rèn)為有以下幾點(diǎn):
-
描述符多,不容易記憶,掌握 要深入了解還有看DTD文件
-
無法做自動校驗,需要人工查找
-
讀取和解析xml配置要消耗一定時間,導(dǎo)致應(yīng)用啟動慢,不便于測試和維護(hù)
-
當(dāng)系統(tǒng)很大時,大量的xml文件難以管理
-
運(yùn)行中保存xml配置需要消耗額外的內(nèi)存
-
在O/R Mapping的時候需要在java文件和xml配置文件之間交替,增大了工作量
其中第一 二點(diǎn) 借助于先進(jìn)的IDE 可能不是什么問題. 但是對初學(xué)者還是個問題 ^_^.
下面我們看看 Annotations的 特性吧! 可以解決xml遇到的問題,有以下優(yōu)點(diǎn)
描述符減少。以前在xml配置中往往需要描述java屬性的類型,關(guān)系等等。而元數(shù)據(jù)本身就是java語言,從而省略了大量的描述符
編譯期校驗。錯誤的批注在編譯期間就會報錯。
元數(shù)據(jù)批注在java代碼中,避免了額外的文件維護(hù)工作
元數(shù)據(jù)被編譯成java bytecode,消耗的內(nèi)存少,讀取也很快,利于測試和維護(hù)
關(guān)于 映射文件是使用 hbm.xml 文件還是使用 Annotations 我們來看看2者的性能吧. 先聲明一下,個人認(rèn)為映射文件一旦配置好就不會在很大程度上改變了.所以使用xml文件并不會帶來很大的好處.如果你認(rèn)為 映射文件在你的項目中也經(jīng)常變化,比如一列String數(shù)據(jù) ,今天你使用 length="16" 明天你認(rèn)為 該數(shù)據(jù)的長度應(yīng)該更長才能滿足業(yè)務(wù)需求 于是改為length="128" 等等類似的問題 . 如果你經(jīng)常有這方面的變動的話,下面的比較你可以不用看了 , 你應(yīng)該使用 xml文件 因為Annotations 無法很好的滿足你的要求.
現(xiàn)在讓我們就來看看2者的性能比較吧.
(說明: 這里只是比較查找 插入 的時間快慢,沒有比較除運(yùn)行時間以外的其他性能,如 內(nèi)存占用量 等等)
先來看看測試程序和配置.
首先在 Hibernate.cfg.xml 文件中去掉了
<property name="hibernate.hbm2ddl.auto">update</property>
這一行, 因為在前面的實(shí)驗中以及建立了數(shù)據(jù)庫表了 不再需要更新了.如果你是第一次運(yùn)行該例子 還是要該行的.
Test.java 如下:
/*
?*?Created?on?2005
?*?@author?
?*/
package?test.hibernate.annotation;
import?org.hibernate.Session;
import?org.hibernate.Transaction;
public?class?Test?{
??
??public?static?void?main(String?[]?args)?{
????long?start?=?0;
????long?end?=?0;
????start?=?System.currentTimeMillis();??//程序開始時間
????
????Session?s?=?HibernateUtil.currentSession();
????long?mid?=??System.currentTimeMillis();??//初始化完畢的時間 (可能此時并沒有初始化完畢^(qū)_^)
????
????Transaction?tx?=?s.beginTransaction();????
????/********************測試讀取的代碼************************/
????Person?p?=?null;
????for(int?i?=?1;?i?<=?100;?i?++)?{
????p?=?(Person)?s.get(Person.class,?i);
????System.out.println(p.getName());
????}
????System.out.println(p.getName());
??? /********************測試讀取1次的代碼************************/
????Person?p?=?null;
????p?=?(Person)?s.get(Person.class,?1);
????System.out.println(p.getName());
????/*********************測試插入的代碼*************************************/
????/*
????for?(int?i?=?0;?i?<?100;?i?++)?{
??????Person?p?=?new?Person();
??????p.setAge(i+1);
??????p.setName("icerain"+i);
??????p.setSex("male"+i);
??????s.save(p);
??????s.flush();
????}
????*/
????tx.commit();
????HibernateUtil.closeSession();
????
????end?=?System.currentTimeMillis();?//測試結(jié)束時間
????System.out.println("String[]?-?start?time:?"?+?start);
????System.out.println("String[]?-?end?time:?"?+?end);
????System.out.println("Init?time?:?"?+?(mid-start)); // 打印初始化用的時間
????System.out.println("Last?time?is?:"?+(end?-?mid)?); //打印 數(shù)據(jù)操作的時間
????System.out.println("Total?time?:?"?+(end?-?start)); //打印總時間
??}
}
Annotations 包中的Person.java 如下
package?test.hibernate.annotation;
import?java.util.LinkedList;
import?java.util.List;
import?javax.persistence.AccessType;
import?javax.persistence.Basic;
import?javax.persistence.Entity;
import?javax.persistence.GeneratorType;
import?javax.persistence.Id;
import?javax.persistence.Table;
import?javax.persistence.Transient;
/**
?*?Person?generated?by?hbm2java
?*/
@SuppressWarnings("serial")
@Entity(access?=?AccessType.PROPERTY)
@Table
public?class?Person?implements?java.io.Serializable?{
??private?Integer?id;
??private?String?name;
??private?String?sex;
??private?Integer?age;
??private?List?list?=?new?LinkedList();
??//?Constructors
??/**?default?constructor?*/
??public?Person()?{
??}
??/**?constructor?with?id?*/
??public?Person(Integer?id)?{
????this.id?=?id;
??}
??//?Property?accessors
??@Id(generate=GeneratorType.AUTO)
??public?Integer?getId()?{
????return?this.id;
??}
??public?void?setId(Integer?id)?{
????this.id?=?id;
??}
??@Basic
??public?String?getName()?{
????return?this.name;
??}
??public?void?setName(String?name)?{
????this.name?=?name;
??}
??@Basic
??public?String?getSex()?{
????return?this.sex;
??}
??public?void?setSex(String?sex)?{
????this.sex?=?sex;
??}
??@Basic
??public?Integer?getAge()?{
????return?this.age;
??}
??public?void?setAge(Integer?age)?{
????this.age?=?age;
??}
??@Transient
??public?List?getList()?{
????return?list;
??}
??public?void?setList(List?list)?{
????this.list?=?list;
??}
}
其他的代碼幾乎沒有改變:
下面的每種類型的測試都測試了3次以上, 取中間的測試時間.
測試機(jī)器配置:
CPU:? AMD Athlon (xp) 2000+
內(nèi)存: 784880KB
硬盤: 三星 SP0812N
讀取一次??的比較:(單位: 毫秒)
使用Annotations 的測試數(shù)據(jù) | 使用Xml文件的測試數(shù)據(jù) | 簡要說明 |
Init time : | 2444 | Init time : | 2431 | 測試前我認(rèn)為該項結(jié)果xml應(yīng)該比較大,要讀取映射文件啊,實(shí)際情況不是這樣,不知道為什么? |
Last time is : | 62 | Last time is : | 85 | 相差比較大不知道為什么? |
Total time : | 2506 | Total time : | 2516 | xml文件總體上慢了一點(diǎn) |
?? 讀取100次的比較:
使用Annotations 的測試數(shù)據(jù) | 使用Xml文件的測試數(shù)據(jù) | 簡要說明 |
Init time : | 2437 | Init time : | 2422 | 和前面初始化差不多 |
Last time is : | 438 | Last time is : | 484 | 有時間差 |
Total time : | 2875 | Total time : | 2906 | 也是xml文件總體上慢了一點(diǎn) |
插入100次的比較:
使用Annotations 的測試數(shù)據(jù) | 使用Xml文件的測試數(shù)據(jù) | 簡要說明 |
Init time : | 2453 | Init time : | 2469 | 和前面初始化差不多 |
Last time is : | 469 | Last time is : | 656 | 有時間差 |
Total time : | 2922 | Total time : | 3125 | 也是xml文件總體上慢了一點(diǎn) |
從上面的三次對比中大家可以看到 初始化的部分幾乎兩者是一樣的, 在數(shù)據(jù)操作上面 使用xml文件 總是比使用Annotations 慢一點(diǎn).在我們只操縱一個只有幾個屬性的小持久化類的操作中就有 幾十毫秒的差距. 幾十毫秒在計算機(jī)中算不算很大 大家應(yīng)該都知道,我就不在多說了.
總結(jié): 經(jīng)過 xml 文件 和Annotations 的優(yōu)缺點(diǎn)和 性能上的對比.現(xiàn)在使用那個作為你持久化映射策略.我相信大家都會正確選擇的.
測試后記: 經(jīng)過多次測試 感覺有時候很不穩(wěn)定 ,有的時候很穩(wěn)定不知道是測試有問題還是別的問題.大家可以自己測試一下. 有什么新的發(fā)現(xiàn) 請大家討論討論.