EJB (Entity EnterPRise javaBeans) 是一種可以把持久性數(shù)據(jù)映射到Java組件上的簡便方法。CMP (Container-Managed persistence)提供了快速開發(fā)功能,這是因?yàn)镋JB 容器可自動(dòng)處理持久性數(shù)據(jù)的加載和存儲(chǔ)。然而,在具有許多優(yōu)點(diǎn)的同時(shí),假如Entity EJB沒有正確使用,也會(huì)導(dǎo)致性能的大幅下降。本文具體介紹了幾個(gè)常見的編程缺陷,它們經(jīng)常使EJB的程序員犯錯(cuò),并妨礙其實(shí)體(Entity)beans的性能。
Primary Key類
類似于數(shù)據(jù)庫中的行,實(shí)體beans有一個(gè)主鍵(primary key)與它關(guān)聯(lián)。這個(gè)主鍵可以是實(shí)體bean的一個(gè)單一字段。在這種情況下,實(shí)體bean可以用字段的類作為主鍵。
還可能提供一種自定義的主鍵類。對于復(fù)合主鍵來說,必須定制一個(gè)主鍵類,來映射多個(gè)實(shí)體bean的字段。
使用定制的主鍵類,開發(fā)人員必須實(shí)現(xiàn)hashCode和equals方法。因?yàn)镋JB容器常在其內(nèi)部數(shù)據(jù)結(jié)構(gòu)中使用主鍵類,所以這個(gè)類必須正確和有效的實(shí)現(xiàn)hashCode和equals方法 (參見清單1)。
清單 1:
一個(gè)低效但正確的主鍵類
public class MyPk
implements java.io.Serializable
{
public String str;
public int i;
public byte b;
public MyPk() {}
public int hashCode() { return -1; }
public boolean equals(Object o) {
if ((o != null) && (MyPk.class.equals(o.getClass()))) {
MyPk other = (MyPk) o;
return other.str.equals(str) && other.i == i && other.b == b;
} else {
return false;
}}
}
實(shí)現(xiàn)hashCode方法
hashCode方法對于兩個(gè)equal的對象,必須返回相同的值,而且應(yīng)該相對均勻地分配哈希值。下面顯示的第一種實(shí)現(xiàn)方法正確而有效,但是根本沒有分配哈希值。這個(gè)hashCode實(shí)現(xiàn)把全部哈希表變換到一個(gè)列表中,而且必須線性檢索。顯然,這樣違反了可檢索性數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)初衷。
private int hash = -1;
public int hashCode() {
if (hash == -1) {
hash = str.hashCode() ^ i ^ b;
}
return hash;
}
上面的hashCode實(shí)現(xiàn)計(jì)算了字符串的哈希值和原字段的異或(XOR)值。 與其它的邏輯運(yùn)算符相比,諸如AND和OR,XOR應(yīng)該是更可取的,因?yàn)樗梢愿玫胤峙涔V?。這種實(shí)現(xiàn)還可以把哈希值緩存在一個(gè)成員變量中,以避免重復(fù)計(jì)算這個(gè)值。
實(shí)現(xiàn)Equals 方法
equals方法的功能是使用傳入的參數(shù)比較當(dāng)前對象,假如對象有相同的值,就返回true。默認(rèn)的java.lang.Object.equals用于比較引用(指針)值,假如它們相等就返回true。對于大多數(shù)的主鍵類,需要重寫這個(gè)方法,以便在主鍵類中比較這些值(參見清單 2)。
清單:2
一個(gè)有效的equals實(shí)現(xiàn)
public final class MyPk ...
public boolean equals(Object o) {
if (o == this) return true;
if (o instanceof MyPk) {
MyPk other = (MyPk) o;
return other.hashCode() == hashCode() &&
other.i == i && other.b == b &&
other.str.equals(str);
} else {
return false;
}}
這是一種優(yōu)化的equals實(shí)現(xiàn),它的第一行用與此相反的方式比較傳入的引用。第一,雖然這看起來有點(diǎn)生疏,但這是EJB容器檢查一個(gè)主鍵是否已經(jīng)在它的數(shù)據(jù)結(jié)構(gòu)中存在的常用方法。
第二,我們已經(jīng)用一個(gè)更有效的檢查實(shí)例替代了getClass().equals。假如傳入?yún)?shù)的類是MyPk類或它的一個(gè)子類,操作符的實(shí)例將返回true。 用final修飾MyPk類,這樣創(chuàng)建的方法可以安全地使用操作符的實(shí)例,因?yàn)檫@樣就不存在子類了。
最后,比較哈希表和成員變量。Java中的表達(dá)式具有短路功能,這意味著假如第一個(gè)表達(dá)式是false,第二個(gè)表達(dá)式將不再計(jì)算。這個(gè)equals方法很好的利用了這一點(diǎn),先用最簡易的比較調(diào)整了and語句的順序。在這個(gè)例子里,首先比較的是哈希值,這是因?yàn)槲覀兊膶?shí)現(xiàn)緩存了這個(gè)值,而且發(fā)生兩個(gè)對象具有相同的hashCode但卻不相等的情況很少。接下來比較的是原始字段;最后是調(diào)用花費(fèi)資源最多的java.lang.String.equals。
加載和存儲(chǔ)實(shí)體beans
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注