Hibernate Annotations 實(shí)戰(二)
-- hbm.xml 與 Annotations 性能比較
任何獲得Matrix授權的網(wǎng)站,轉載請保留以下作者信息和鏈接:
作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
關(guān)鍵字:Hibernate Validator
我在前面一篇文章<Hibernate Annotations 實(shí)戰-- 從 hbm.xml 到 Annotations>:
中,有很多開(kāi)發(fā)者在談?wù)撝刑岬?有沒(méi)有必要從 hbm.xml 往 Annotations 上轉移. 那么在這篇文章中我們就來(lái)討論一下 hbm.xml 與 Annotations的優(yōu)缺點(diǎn),看看那種情況最適合你.
首先,討論一下 xml 配置文件的優(yōu)點(diǎn), 個(gè)人認為主要優(yōu)點(diǎn)就是當你改變底層配置時(shí) 不需要改變和重新編譯代碼,只需要在xml 中更改就可以了,例如 Hibernate.cfg.xml 當你要更改底層數據庫時(shí), 只要更改配置文件就可以了.Hibernate會(huì )為你做好別的事情.
那么xml的缺點(diǎn)呢,個(gè)人認為有以下幾點(diǎn):
描述符多,不容易記憶,掌握 要深入了解還有看DTD文件
無(wú)法做自動(dòng)校驗,需要人工查找
讀取和解析xml配置要消耗一定時(shí)間,導致應用啟動(dòng)慢,不便于測試和維護
當系統很大時(shí),大量的xml文件難以管理
運行中保存xml配置需要消耗額外的內存
在O/R Mapping的時(shí)候需要在java文件和xml配置文件之間交替,增大了工作量
其中第一 二點(diǎn) 借助于先進(jìn)的IDE 可能不是什么問(wèn)題. 但是對初學(xué)者還是個(gè)問(wèn)題 ^_^.
下面我們看看 Annotations的 特性吧! 可以解決xml遇到的問(wèn)題,有以下優(yōu)點(diǎn)
描述符減少。以前在xml配置中往往需要描述java屬性的類(lèi)型,關(guān)系等等。而元數據本身就是java語(yǔ)言,從而省略了大量的描述符
編譯期校驗。錯誤的批注在編譯期間就會(huì )報錯。
元數據批注在java代碼中,避免了額外的文件維護工作
元數據被編譯成java bytecode,消耗的內存少,讀取也很快,利于測試和維護
關(guān)于 映射文件是使用 hbm.xml 文件還是使用 Annotations 我們來(lái)看看2者的性能吧. 先聲明一下,個(gè)人認為映射文件一旦配置好就不會(huì )在很大程度上改變了.所以使用xml文件并不會(huì )帶來(lái)很大的好處.如果你認為 映射文件在你的項目中也經(jīng)常變化,比如一列String數據 ,今天你使用 length="16" 明天你認為 該數據的長(cháng)度應該更長(cháng)才能滿(mǎn)足業(yè)務(wù)需求 于是改為length="128" 等等類(lèi)似的問(wèn)題 . 如果你經(jīng)常有這方面的變動(dòng)的話(huà),下面的比較你可以不用看了 , 你應該使用 xml文件 因為Annotations 無(wú)法很好的滿(mǎn)足你的要求.
現在讓我們就來(lái)看看2者的性能比較吧.
(說(shuō)明: 這里只是比較查找 插入 的時(shí)間快慢,沒(méi)有比較除運行時(shí)間以外的其他性能,如 內存占用量 等等)
先來(lái)看看測試程序和配置.
首先在 Hibernate.cfg.xml 文件中去掉了
<
property name="hibernate.hbm2ddl.auto">update</property>這一行, 因為在前面的實(shí)驗中以及建立了數據庫表了 不再需要更新了.如果你是第一次運行該例子 還是要該行的.
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(); //程序開(kāi)始時(shí)間
Session s = HibernateUtil.currentSession();
long mid = System.currentTimeMillis(); //初始化完畢的時(shí)間 (可能此時(shí)并沒(méi)有初始化完畢^_^)
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(); //測試結束時(shí)間
System.out.println("String[] - start time: " + start);
System.out.println("String[] - end time: " + end);
System.out.println("Init time : " + (mid-start)); // 打印初始化用的時(shí)間
System.out.println("Last time is :" +(end - mid) ); //打印 數據操作的時(shí)間
System.out.println("Total time : " +(end - start)); //打印總時(shí)間
}
}
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;
}
}
其他的代碼幾乎沒(méi)有改變:
下面的每種類(lèi)型的測試都測試了3次以上, 取中間的測試時(shí)間.
測試機器配置:
CPU: AMD Athlon (xp) 2000+
內存: 784880KB
硬盤(pán): 三星 SP0812N
讀取一次 的比較:(單位: 毫秒)
| 使用Annotations 的測試數據 | 使用Xml文件的測試數據 | 簡(jiǎn)要說(shuō)明 | ||
| Init time : | 2444 | Init time : | 2431 | 測試前我認為該項結果xml應該比較大,要讀取映射文件啊,實(shí)際情況不是這樣,不知道為什么? |
| Last time is : | 62 | Last time is : | 85 | 相差比較大不知道為什么? |
| Total time : | 2506 | Total time : | 2516 | xml文件總體上慢了一點(diǎn) |
讀取100次的比較:
| 使用Annotations 的測試數據 | 使用Xml文件的測試數據 | 簡(jiǎn)要說(shuō)明 | ||
| Init time : | 2437 | Init time : | 2422 | 和前面初始化差不多 |
| Last time is : | 438 | Last time is : | 484 | 有時(shí)間差 |
| Total time : | 2875 | Total time : | 2906 | 也是xml文件總體上慢了一點(diǎn) |
插入100次的比較:
| 使用Annotations 的測試數據 | 使用Xml文件的測試數據 | 簡(jiǎn)要說(shuō)明 | ||
| Init time : | 2453 | Init time : | 2469 | 和前面初始化差不多 |
| Last time is : | 469 | Last time is : | 656 | 有時(shí)間差 |
| Total time : | 2922 | Total time : | 3125 | 也是xml文件總體上慢了一點(diǎn) |
從上面的三次對比中大家可以看到 初始化的部分幾乎兩者是一樣的, 在數據操作上面 使用xml文件 總是比使用Annotations 慢一點(diǎn).在我們只操縱一個(gè)只有幾個(gè)屬性的小持久化類(lèi)的操作中就有 幾十毫秒的差距. 幾十毫秒在計算機中算不算很大 大家應該都知道,我就不在多說(shuō)了.
總結: 經(jīng)過(guò) xml 文件 和Annotations 的優(yōu)缺點(diǎn)和 性能上的對比.現在使用那個(gè)作為你持久化映射策略.我相信大家都會(huì )正確選擇的.
測試后記: 經(jīng)過(guò)多次測試 感覺(jué)有時(shí)候很不穩定 ,有的時(shí)候很穩定不知道是測試有問(wèn)題還是別的問(wèn)題.大家可以自己測試一下. 有什么新的發(fā)現 請大家討論討論
聯(lián)系客服