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