天天看點

Hibernate常見異常解答(轉)

1問:Hibernate初始化時總是報錯:java.lang.NoClassDefFoundError

Hibernate初始化時出現出錯代碼:

java.lang.NoClassDefFoundError: net/[size=medium][/size]sf/ehcache/CacheException

答:這是新手常見問題。是因為使用預設設定時,Hibernate文檔裡指出的Hibernate庫不完整,缺少ehcache.jar(用于支援Ehcache的相關檔案)。配置中加入以上檔案,就可以避免初始化時出現java.lang.NoClassDefFoundError:net/sf/ehcache/CacheException異常。

2問:Hibernate報錯:"Not binding factory to JNDI, no JNDI name configured"

運作下列程式:

public static void main(String[] args) throws Exception {

Configuration conf = new Configuration().addClass(Person.class);

......

出現錯誤碼:

12:15:34,250 INFO SessionFactoryObjectFactory:82 - Not binding factory to JNDI, no JNDI name configured

java.lang.UnsupportedOperationException: The user must supply a JDBC connection

at net.sf.Hibernate.connection.UserSuppliedConnectionProvider.getConnection (UserSuppliedConnectionProvider.java:32)

at net.sf.Hibernate.impl.BatcherImpl.openConnection(BatcherImpl.java:289)

at net.sf.Hibernate.impl.SessionImpl.connect(SessionImpl.java:3361)

at net.sf.Hibernate.impl.SessionImpl.connection(SessionImpl.java:3321)

at net.sf.Hibernate.impl.BatcherImpl.prepareQueryStatement(BatcherImpl.java:66)

at net.sf.Hibernate.loader.Loader.prepareQueryStatement(Loader.java:779)

at net.sf.Hibernate.hql.QueryTranslator.iterate(QueryTranslator.java:864)

at net.sf.Hibernate.impl.SessionImpl.iterate(SessionImpl.java:1618)

at net.sf.Hibernate.impl.QueryImpl.iterate(QueryImpl.java:27)

at com.Hibernate.person.TestQueryPerson.main(TestQueryPerson.java:28)

Exception in thread "main"

答:修改main函數,為該程式指定配置檔案即可。

public static void main(String[] args) throws Exception {

File file=new File("./Hibernate.cfg.xml");

Configuration conf = new Configuration().configure(file);

......

配置檔案如下。

<?xml version="1.0"?>

<!DOCTYPE Hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://Hibernate.sourceforge.net/Hibernate-mapping-3.0.dtd">

<!--

This mapping demonstrates content-based discrimination for the

table-per-hierarchy mapping strategy, using a formula

discriminator.

-->

<Hibernate-mapping package="org.Hibernate.test.array">

<class name="A" lazy="true">

<id name="id">

<generator class="native"/>

</id>

<array name="bs" cascade="all" fetch="join">

<key column="a_id"/>

<list-index column="idx"/>

<one-to-many class="B"/>

</array>

</class>

<class name="B" lazy="true">

<id name="id">

<generator class="native"/>

</id>

</class>

</Hibernate-mapping>

3問:使用開發工具Elipse,運作時總報java.lang.NoClassDefFoundError: org/ Hibernate/Session異常

使用Elipse,所用包是hibernte 3,發現在Action中每次執行到:

session=HibernateSessionFactory.currentSession();

時,出現java.lang.NoClassDefFoundError: org/Hibernate/Session異常,如下:

java.lang.NoClassDefFoundError: org/Hibernate/Session

Hibernate3.Hibernate.ExcuteClass.search(ExcuteClass.java:17)

Hibernate3.Hibernate.ExcuteClass.test3(ExcuteClass.java:13)

Hibernate3.Hibernate.Svlt.doGet(Svlt.java:50)

javax.servlet.http.HttpServlet.service(HttpServlet.java:689)

javax.servlet.http.HttpServlet.service(HttpServlet.java:802)[/b]

答:這是初學者常見問題,原因是沒有導入hibernate 3.jar包,雖然把hibernate 3.jar寫入了Classpath,但部署的時候卻沒有拷貝到lib下面,可以手動拷貝進入。

4問:執行如下方法時,發生"No CurrentSessionContext configured"錯誤

執行如下方法時,發生"No CurrentSessionContext configured"錯誤:

Public static Session currentSession() {

try {

System.out.println("HibernateUtil.currentSession() - start");

return getSessionFactory().getCurrentSession();

} catch (HibernateException ex) {

System.out.println("HibernateUtil.currentSession() - failed due to " + ex);

throw ex;

}

}

答:這個錯誤是由配置檔案引起。在內建Hibernate的環境下(例如Jboss),在session-factory段加入:

<property name="Hibernate.current_session_context_class">jta</property>

在不內建Hibernate的環境下(例如使用JDBC的獨立應用程式),在session-factory段加入:

<property name="Hibernate.current_session_context_class">thread</property>

就可以解決這個問題。

5問:移植Jboss 4下配置Hibernate出錯

在Tomcat 5下配置Hibernate成功,但移植到Jboss 4下出現了很多問題。已在deploy目錄下放置了Hibernate-service.xml和Hibernate.cfg.xml檔案,但啟動伺服器仍然報錯 如下。

16:56:54,046 ERROR [URLDeploymentScanner] Incomplete Deployment listing:

Packages waiting for a deployer:

org.Jboss.deploym[email protected] { url=file:/C:/Downloads/temp/Jboss-

4.0.0/server/default/deploy/Hibernate.cfg.xml }

deployer: null

status: null

state: INIT_WAITING_DEPLOYER

watch: file:/C:/Downloads/temp/Jboss-4.0.0/server/default/deploy/Hibernate.cfg

.xml

altDD: null

lastDeployed: 1113987414046

lastModified: 1113987414046

mbeans:

Incompletely deployed packages:

org.Jboss.deploym[email protected] { url=file:/C:/Downloads/temp/Jboss-

4.0.0/server/default/deploy/Hibernate.cfg.xml }

deployer: null

status: null

state: INIT_WAITING_DEPLOYER

watch: file:/C:/Downloads/temp/Jboss-4.0.0/server/default/deploy/Hibernate.cfg

.xml

altDD: null

lastDeployed: 1113987414046

lastModified: 1113987414046

mbeans:

答:這是在Jboss中使用Hibernate的常見問題。在Jboss的某個war包中使用Hibernate應該将Hibernate.cfg.xml檔案放置到%war_dir%WEB-INF/classes中,但是Hibernate的factory仍然可能會提示Hibernate.cfg.xml not found。此問題解決方法如下。

由于Jboss已經內建了Hibernate,在deploy\lib檔案夾中hibernate2.jar的檔案已經存在了一個jar包,是以實際的war中可能使用了shar的hibernate2.jar,由于ClassLoader隻會在hibernate2.jar的同級及上級目錄中尋找hibernate.cfg.xml,是以導緻Hibernate并沒有去查找%war_dir%WEB-INF/classes中的Hibernate.cfg.xml檔案。删除deploy/lib下的hibernate2.jar或者使用絕對路徑指定Hibernate.cfg.xml可以解決。

除非有其他需求,否則在Jboss下部署Hibernate與在Tomcat下是一樣的,并不需要加其他配置檔案。

6問:到底在哪裡使用cascade="..."?

答:cascade屬性并不是多對多關系一定要用的,用了它隻是插入或删除對象時更友善一些,隻要在cascade的源頭上插入或删除,所有cascade的關系就會被自動插入或删除。其中unsaved-value是個很重要的屬性,Hibernate是通過這個屬性來判斷這個對象應該“save”還是“update”,如果這個對象的id是unsaved-value,那說明這個對象不是persistence object,要save(insert);如果id是非unsaved-value,那說明這個對象是persistence object(資料庫中已存在),隻要update就行了。

7問:到底在哪裡使用inverse="true"

答:inverse屬性預設是false,就是說關系的兩端都來維護關系。這個意思就是說,如有3個表:Student、Teacher和TeacherStudent,Student對象和Teacher對象是多對多關系,這個關系由TeacherStudent表來表現。

那麼什麼時候插入或删除TeacherStudent表中的記錄呢。用Hibernate時,不會顯式的對TeacherStudent表操作,對TeacherStudent的操作是Hibernate自動做的。Hibernate就是hbm檔案中指定的是“誰”維護關系,在插入或删除時,就會觸發對關系表的操作。前提是“誰”這個對象已經知道這個關系,就是說關系另一頭的對象已經set或是add到“誰”這個對象裡來。

前面說過inverse預設是false,就是關系的兩端都維護關系,對其中任一個操作都會觸發對表的操作。當在關系的一頭,如Student中的bag或set中用了inverse="true"時,就代表關系是由另一端維護的(Teacher)。就是說當插入Student時,不會操作TeacherStudent表,即使Student已經知道了關系。隻有Teacher插入或删除時才會觸發對關系表的操作。是以,關系的兩頭都用inverse="true"是不對的,會導緻任何操作都不觸發對關系表的操作。當兩端都是inverse="false"或是default值時,在代碼中對關系顯式的維護也是不對的,會導緻在關系表中插入兩次關系。

8問:Cascade和Inverse有什麼差別?

答:可以這樣了解,Cascade定義的是關系兩端對象到對象的級聯關系;而Inverse定義的是關系和對象的級聯關系。

9問:在删除操作時報錯:net.sf.Hibernate.ObjectDeletedException:deleted object would be re-saved by cascade (remove deleted object from associations)

答:要删除關系的一頭時(如,要删除一個已經和Student對象有關聯的Teacher對象),當tx.commit()時才會抛出這個異常。防止出現這個異常的方法如下。

在Student端不用cascade。

或是用cascade的話,就顯式的删除對像中的關系。

在Teacher端要用cascade。

10問:出現net.sf.Hibernate.HibernateException: identifier of an instance of my. MyObject altered from N to N異常

答:這個異常不是多對多關系中常遇到的,但是這個異常的提示容易讓人混淆。這是因為在Java對象中,id定義和hbm檔案的不一樣。如Java中用long,而hbm中用type= "integer"。

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: <classname>

答:Hibernate 3的預設方式是把所有類通過代理方式來進行延遲加載。如果代碼中的類有一個私有無參的構造器的話,Hibernate将無法在運作時将項目代碼中的類作為子類裝載。為了避免這個錯誤,類中的構造器函數至少應該在包内可見。

19問:為什麼在Hibernate中添加、删除、修改一個對象或Collection,但是資料庫中實際上沒有任何變化

答:這個問題經常會困擾初學者。這是因為如果沒有使用Hibernate的自動事務處理,則必需顯式的送出事務,操作才會在資料庫中執行。

20問:為什麼儲存一個父對象,而它的關聯對象沒有自動儲存到資料庫裡

答:關聯對象必需顯式的調用session.save()(或session.persist()),或者在關聯的映射檔案中加入cascade="all"或cascade="save-update"(或cascade="persist")才能夠自動關聯執行。