教育行業(yè)A股IPO第一股(股票代碼 003032)

全國(guó)咨詢/投訴熱線:400-618-4000

Java培訓(xùn)實(shí)戰(zhàn)教程之Hibernate使用Oracle數(shù)據(jù)庫(kù)遇到的幾個(gè)問(wèn)題

更新時(shí)間:2015年12月29日13時(shí)22分 來(lái)源:傳智播客Java培訓(xùn)學(xué)院 瀏覽次數(shù):

 
前言
Hibernate作為一個(gè)成熟的持久層解決方案,通過(guò)簡(jiǎn)單的配置,可以在不修改源碼的情況下,無(wú)縫的在不同的數(shù)據(jù)庫(kù)上運(yùn)行。盡管如此,使用不同的數(shù)據(jù)庫(kù)仍然會(huì)出現(xiàn)一些問(wèn)題,比如本文要討論的Oracle中的問(wèn)題。
 
1.   Hibernate無(wú)法創(chuàng)建hibernate_sequence的問(wèn)題
錯(cuò)誤提示:
 
問(wèn)題分析:
從錯(cuò)誤提示上看,查詢語(yǔ)句沒(méi)有找到hibernate_sequence這個(gè)序列。到Oracle數(shù)據(jù)庫(kù)中查看,果然沒(méi)有。按道理說(shuō),hibernate應(yīng)該在Oracle中自動(dòng)生成這個(gè)序列,那為什么沒(méi)有生成呢?原因主要有兩個(gè):
1.hibernate的核心配置中沒(méi)有設(shè)置自動(dòng)建對(duì)象的屬性,導(dǎo)致無(wú)法自動(dòng)建立序列:
<property name="hibernate.hbm2ddl.auto">update</property>
 
2.其他用戶存在hibernate_sequence這個(gè)序列,導(dǎo)致當(dāng)前用戶不再創(chuàng)建該序列。
原因:
hibernate在啟動(dòng)時(shí)即需要去檢測(cè)所要?jiǎng)?chuàng)建的序列是否存在,如果存在,則不再創(chuàng)建此序列。在某些情況下,hibernate能夠探測(cè)到其它用戶所創(chuàng)建的同名序列,而被認(rèn)為不再需要?jiǎng)?chuàng)建序列,這時(shí)候如果進(jìn)行保存數(shù)據(jù)的操作,就會(huì)因?yàn)樵诋?dāng)前用戶下找不到該序列從而導(dǎo)致出錯(cuò)。
要解決這個(gè)問(wèn)題的首要方法是需要找到hibernate判斷指定序列是否存在的方法,在hibernate的dialet中,取決于getQuerySequencesString這個(gè)方法,此方法返回了查詢所有序列的方法。
Hibernate中的與Oracle相關(guān)dialet一般配置為Oracle10gDialect、Oracle9iDialect、Oracle8iDialect。從源碼我們可以看到他們之間是繼承關(guān)系,如:Oracle10gDialect extend Oracle9iDialect extend Oracle8iDialect extend Dialet。通過(guò)源代碼我們可以看出,該方法只是在Oracle8iDialect中進(jìn)行了覆寫(xiě),其子類都沿用了該實(shí)現(xiàn)。實(shí)現(xiàn)代碼如下:
public String getQuerySequencesString() {
       return    " select sequence_name from all_sequences"
              + "  union"
              + " select synonym_name"
              + "   from all_synonyms us, all_sequences asq"
              + "  where asq.sequence_name = us.table_name"
              + "    and asq.sequence_owner = us.table_owner";
    }
從代碼分析看,它是從all_sequence中尋找所能找到的sequence,而當(dāng)前用戶能找到的sequence全在于當(dāng)前用戶能有多大的權(quán)限,以及具體的oracle jdbc實(shí)現(xiàn)。在這種情況下,如果當(dāng)前用戶擁有dba權(quán)限(開(kāi)發(fā)時(shí)候,經(jīng)常給一個(gè)用戶授dba權(quán)限)或者由于其它某種原因,就能夠找到其他用戶的sequence了。而如果其他用戶也創(chuàng)建了一個(gè)叫hibernate_sequence的sequence,那hibernate在當(dāng)前用戶就不能再創(chuàng)建sequence了。
 
知道了這個(gè)原因后,如何解決呢?
我們可以創(chuàng)建一個(gè)新的OracleDialect,直接繼承于Oracle10gDialect,并在新的類中覆蓋getQuerySequencesString方法,將其中的sql語(yǔ)句改為從user_sequences(即當(dāng)前用戶的sequence空間)中尋找相應(yīng)的序列,這樣就不會(huì)尋找到其它用戶的序列了。參考代碼如下:
public class Oracle10gDialectEx extends Oracle10gDialect {
public String getQuerySequencesString() {
        return "select sequence_name from user_sequences";
    }
}
 
還有個(gè)解決辦法,就是去掉該Oracle用戶的跨用戶訪問(wèn)的權(quán)限,如select any table的權(quán)限或dba角色。
 
 
2.   使用hibernate生成表不能正確創(chuàng)建表的問(wèn)題
問(wèn)題:
hbm2ddl.auto配置成update時(shí),發(fā)現(xiàn)hibernate并沒(méi)有按照默認(rèn)的生成規(guī)則生成相應(yīng)的數(shù)據(jù)表信息
分析發(fā)現(xiàn),這里需要引用的表p_menu在另一個(gè)用戶空間里已經(jīng)存在了,而hibernate在創(chuàng)建表時(shí),在另一個(gè)用戶空間中找到了這個(gè)表,故不再在當(dāng)前的用戶空間中創(chuàng)建這個(gè)表了。而在創(chuàng)建關(guān)聯(lián)表時(shí),由于關(guān)聯(lián)的是本用戶空間的表,故有此錯(cuò)誤。
hibernate使用了jdbc默認(rèn)的databasemeta來(lái)尋找相應(yīng)表數(shù)據(jù)信息,當(dāng)使用默認(rèn)的配置時(shí),由于某種原因(并不是每次都能發(fā)生,取決于數(shù)據(jù)庫(kù)本身以及相應(yīng)的驅(qū)動(dòng))。當(dāng)使用當(dāng)前用戶連接到數(shù)據(jù)庫(kù)時(shí),使用databasemeta尋找數(shù)據(jù)庫(kù)表信息時(shí),會(huì)查詢出其它用戶的數(shù)據(jù)表信息(即使當(dāng)前用戶沒(méi)有相應(yīng)的權(quán)限)。
 
兩種解決方案:
1.在hibernate核心配置中配置一個(gè)屬性:
<property name="hibernate.default_schema">當(dāng)前連接用戶</property>
2.在hbm文件配置中的class元素中指定schema=""的屬性
<class name="class"  table="table" schema="當(dāng)前連接用戶">
3.去掉該Oracle用戶的跨用戶訪問(wèn)的權(quán)限,如select any table的權(quán)限
 
 
3.   SSH啟動(dòng)中的輸出日志中有createClob的info信息的問(wèn)題
 
在使用SSH+Oracle啟動(dòng)的時(shí)候,控制臺(tái)會(huì)打?。?br /> INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
如果是使用的Oracle10G,實(shí)體類使用了Clob字段的時(shí)候,會(huì)拋出這個(gè)信息。
如果使用的是Oracle11G,實(shí)體類使用了復(fù)雜的數(shù)據(jù)類型的時(shí)候,也會(huì)拋出這個(gè)信息。
分析:
這個(gè)東西只是個(gè) INFO 級(jí)別的,也就是說(shuō)僅僅是提醒,無(wú)關(guān)緊要的。但總覺(jué)的不爽。如何解決呢?
從驅(qū)動(dòng)上尋找解決方案:
使用Oracle10G,將默認(rèn)的JDBC驅(qū)動(dòng)ojdbc14升級(jí)為更高版本,如Oracle11G的ojdbc6.jar的版本。
從hibernate上尋找解決方案:
修改hibernate配置項(xiàng)hibernate.temp.use_jdbc_metadata_defaults=false。
另外:Hibernate4的官方資料里說(shuō)11g和10g都是Oracle10gDialect,方言通用,這個(gè)沒(méi)啥影響。
網(wǎng)上參考:http://stackoverflow.com/questions/4588755/hibernate-disabling-contextual-lob-creation-as-createclob-method-threw-error
 
 
本文版權(quán)歸傳智播客Java培訓(xùn)學(xué)院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明作者出處。謝謝!
作者:傳智播客Java培訓(xùn)學(xué)院
首發(fā):http://metathetuscanyresort.com/javaee 

0 分享到:
和我們?cè)诰€交談!