Ibatis 性能優化(2)

最近測試發現個IBatis 有個比較嚴重的性能問題, 描述如下:

1. define a bean class
public class Bean {
    private int    id;
    private String desc;
    private long   price;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
    public long getPrice() {
        return price;
    }
    public void setPrice(long price) {
        this.price = price;
    }
}


2. 如果在這個Bean定義中,存在一個屬性沒有 Getter方法  在運行過程中, IBatis 會表現爲把 class Bean 確定成一個ComplexAccessPlan的對象。那麼, IBatis對Bean對象填充SQL執行後的返回結果會造成比較嚴重的性能問題。 複雜對象填充Bean的結果在性能上表現比較差一點。 這個性能差異隨着需要設置屬性數量的增加, 性能成正比的下降。  目前我測試的結果是10個屬性情況下影響大約 5-6%的執行時間, 如果屬性增加到 84個(中文站的offer對象),他的性能會導致超過30%的下降。 具體的原因, 我會如下解釋:


  com.ibatis.sqlmap.engine.accessplan.AccessPlanFactory Line 60

      if (bytecodeEnhancementEnabled) {
        try {
          plan = new EnhancedPropertyAccessPlan(clazz, propertyNames);
        } catch (Throwable t) {
          try {
            plan = new PropertyAccessPlan(clazz, propertyNames);
          } catch (Throwable t2) {
            plan = new ComplexAccessPlan(clazz, propertyNames);
          }
        }
      }

com.ibatis.common.beans.ClassInfo Line256
 public Method getGetter(String propertyName) {
    Method method = (Method) getMethods.get(propertyName);
    if (method == null) {
      throw new ProbeException("There is no READABLE property named '" + propertyName + "' in class '" + className + "'");
    }
    return method;
  }


class EnhancedPropertyAccessPlan/PropertyAccessPlan  call com.ibatis.common.beans.ClassInfo.getGetter(String) that  cause an exception  when a bean have no Getter method, AccessPlan object choose ComplexAccessPlan.

3. 根據以上的代碼, 我們還可以得出如下結論(這是我給IBATIS開發團隊的郵件部分, 不翻譯:)):
 IBtatis automatic decide a simple bean that property have no Getter method to be  Complex type.  IBatis does not prompt any warning  enhancementEnable option will be skipped. I think these ibatis exception handling is not smooth.  and If user's bean loose some Getter method,  a common user does not know why  ibatis performance become bad.
    就是一個對象由於Getter方法的缺失, IBatis把這個對象的當做複雜對象, 從而, 導致enhancementEnable=true(bean對象字節增加功能, 有興趣的同學可以看看CGLIB中BulkBean的使用)的定義失去了任何作用, 進一步導致IBATIS的性能下降。

針對我們發現的問題, 我們建議如下解決問題:
1. 任何被IBatis 使用的對象屬性必須定義完整的Setter/Getter方法
2. 避免使用自定義類型的對象屬性
3. 如果部分屬性需要被適當處理後才能使用的, 比如表中有一個字段price, 但是我們需要使用的是Money對象, 請按如下方式使用。primitivePrice作爲數據庫使用的屬性, price作爲應用程序使用的屬性。
    public class Bean {    
        private Money             price            = null;
        private long              primitivePrice;
        public Money getPrice() {
            if (price == null) {
                this.price = new Money(0, 0);
                this.price.setCent(primitivePrice);
            }
            return price;
        }
      
        public void setPrice(Money price) {
            if (price == null) {
                this.price = new Money(0, 0);
            } else {
                this.price = price;
            }
            this.primitivePrice = price.getCent();
        }
       
        public void setPrimitivePrice(long price) {
            this.primitivePrice = price;
        }
        public long getPrimitivePrice() {
            return this.primitivePrice ;
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章