Hibernate常見的問題(下)
11問:為什麼在向資料庫中插入長字串時候部分自動丟失
在向資料庫中增加一條新的條目時,發現如果文字(有英文字母,也有漢字)數量特別大,超過1000個,則每次通過Hibernate,向一個String型別的欄位中增加資料時,只有幾百個字可以增加進去,其他的自動丟失了。
答:這是由於欄位長度設定不合理造成的。可以根據字串實際長度考慮使用Text、LongText、或者Blob等欄位型別。不同資料庫的欄位型別稍有不同,可以參考相關手冊。另外需要注意的是一個漢字佔用兩個位元組長度。
12問:為什麼採用Hibernate的批量刪除方法來刪除大批量的記錄資料時速度特別慢
答:在使用Hibernate版本2.X時,不推薦採用Hibernate的批量刪除方法來刪除大量記錄。原因是,Hibernate會執行1條查詢語句,另外還有滿足條件的多條刪除語句,而不是一次執行一個刪除語句,所以當待刪除的資料很多時,會有很大的效能瓶頸。而對於Hibernate 3.0以上的版本,則不存這個問題。
13問:升級Hibernate 3後在匯入hbm對映檔案時為什麼非常非常慢
原先在Hibernate 2中,程式的速度是非常快的。當環境順利從Hibernate 2升級到Hibernate 3後,釋出時在Tomcat的控制檯中發現:Hibernate 3裝載hbm對映檔案時非常慢,差不多10秒鐘才能裝載一個hbm檔案。
答:通過在Hibernate的原始碼中設定斷點,可以發現執行效率低下的程式碼在org.hibernate.cfg.Configuration檔案中的第240行:
addInputStream( new FileInputStream( xmlFile ) );
而addInputStream函式中又包含:
org.dom4j.Document doc = xmlHelper.createSAXReader( “XML InputStream”, errors, entityResolver ).read( new InputSource( xmlInputStream ) );
跟蹤org.hibernate.util.XMLHelper中的函式createSAXReader可以得出結論,問題的癥結出在這一條語句:
org.dom4j.Document doc = xmlHelper.createSAXReader()
可以判斷這是在XML檔案裝載初始化時發生的錯誤,仔細檢查XML檔案,可以發現這是XML的第一行宣告dtd的錯誤,因為以前使用的是Hibernate 2,所以hbm檔案的dtd指向的是版本2,而升級Hibernate 3後,沒有把老的hbm對映檔案換成版本3。在更換為3版本後,此問題得到解決。
14問:為什麼Hibernate 3中的HQL無法查詢漢字
使用同樣的程式碼和配置檔案,在Hibernate 2上完全沒有問題,在Hibernate 3中,使用如下HQL查詢,無法得到正確的結果集:
String hql = “from story where title like ‘%漢字%’”;
Query q = session.createQuery(hql);
但用下面的HQL查詢,卻可以得到正確結果集:
String hql = " from story where title like ‘%english%’";
Query q = session.createQuery(hql);
答:如果採用的是拼接HQL的方式,從Hibernate 2升級到Hibernate 3確實會出現漢字亂碼問題。在控制檯中可以看到,SQL的漢字部分變成了亂碼:
[DEBUG] 2005-08-14 14:33:58 org.hibernate.SQL - "select story0_.content from story as story0_ where story0_.title like ‘%&–°é—&&`¨&’
在Hibernate中,查詢時應儘量使用佔位符的寫法(如下),這樣既可以避免亂碼問題,又可以避免潛在的SQL注入攻擊:
getHibernate().find("from story where title like ? ", “%漢字%”)
15問:Hibernate 3中如何獲得庫表所有欄位的名稱
答:可以使用以下的程式獲得。
Configuration conf = new Configuration();
conf.configure();
Iterator iter = conf.getTableMappings();
while ( iter.hasNext() ) {
Table table = ( Table ) iter.next();
System.out.println(table.getName());
Iterator ics = table.getColumnIterator();
while (ics.hasNext()){
Column col = (Column) ics.next();
System.out.println(col.getName());
}
}
16問:錯誤程式碼:ObjectNotFoundException: No row with the given identifier exists
答:在以下幾種情況下,該錯誤可能會發生。
當試圖使用session.load()方法裝載一個未被代理的物件,或者訪問一個超出範圍的代理物件時。
當裝載一個未被正確取得的對映時。
當未被外來鍵約束的外來鍵欄位中含有非法值時。
檢查裝載使用的主鍵Id,並驗證外來鍵關係,以確定資料庫中已經存在相應的約束關係。堅持“在一個Session中只處理一個事務”的原則。因為當在單一Session中使用多個事務時很容易犯錯。尤其注意,在一個HibernateException已經丟擲後不要再操作Session。
17問:錯誤程式碼:InvalidObjectException: Could not find a SessionFactory named: null
答:這個錯誤在以下幾種情況下經常發生。
試圖序列化一個已經失效的Hibernate Session,然後在另外一個虛擬機器中進行反序列化。
類裝載器被重置,例如在未重啟的application server或者Web container中重新部署程式。在使用Tomcat時會經常遇到這個問題,這是因為application server中一般使用JNDI來儲存SessionFactory,而在Tomcat或其他一些Web容器中,則是通過在context過載時,關閉HttpSession序列化來實現的。這種實現方式會引起這個錯誤發生。
18問:錯誤程式碼:org.hibernate.HibernateException: CGLIB Enhancement failed:
答:Hibernate 3的預設方式是把所有類通過代理方式來進行延遲載入。如果程式碼中的類有一個私有無參的構造器的話,Hibernate將無法在執行時將專案程式碼中的類作為子類裝載。為了避免這個錯誤,類中的構造器函式至少應該在包內可見。
19問:為什麼在Hibernate中新增、刪除、修改一個物件或Collection,但是資料庫中實際上沒有任何變化
答:這個問題經常會困擾初學者。這是因為如果沒有使用Hibernate的自動事務處理,則必需顯式的提交事務,操作才會在資料庫中執行。
20問:為什麼儲存一個父物件,而它的關聯物件沒有自動儲存到資料庫裡
答:關聯物件必需顯式的呼叫session.save()(或session.persist()),或者在關聯的對映檔案中加入cascade="all"或cascade=“save-update”(或cascade=“persist”)才能夠自動關聯執行。