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 ;
}
}
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 ;
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.