欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)

 更新時間:2016年07月04日 14:47:02   作者:碼農(nóng)的士首席的哥隊長  
XMLType是Oracle支持的一種基于XML格式存儲的數(shù)據(jù)類型,這里我們共同來探究Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)的方法:

先來了解一下什么是XMLType類型。
XMLType是Oracle從9i開始特有的數(shù)據(jù)類型,是一個繼承了Blob的強(qiáng)大存在,可以用來存儲xml并提供了相當(dāng)多的操作函數(shù)。理論上可以保存2G大小的數(shù)據(jù)。
那怎么樣通過java來插入XMLType類型的數(shù)據(jù)呢?項目當(dāng)中采用的是Mybatis,總是出現(xiàn)莫名的異常,都搞不清楚到底是Mybatis的問題還是jdbc本身的問題,所以打算一步步來,先搞定jdbc,再解決Mybatis。

JDBC
在折騰了半天之后,發(fā)現(xiàn)jdbc操作主要有3種方法:
一、在Java中把XMLType當(dāng)作字符串String來用,具體創(chuàng)建XMLType的任務(wù)完全交給數(shù)據(jù)庫:

String sql = "insert into xmltable (XML) values(sys.xmlType.createXML(?))"; 
String xmldata = "<label>This is an XML fragment</label>"; 
ps.setString(1, xmldata); 
ps.executeUpdate();

此方法會使數(shù)據(jù)庫的壓力偏大,因為此方法簡單又不需要額外的依賴,在一開始采用此方法,但在實際使用過程中發(fā)現(xiàn),在內(nèi)容的長度超過4000左右的時候,會拋出:ORA-01461: can bind a LONG value only for insert into a LONG column 異常。一開始以為使用mybatis的原因,使用jdbc測試依然如此,使用諸多方法嘗試無解。在項目中使用該大字段不可能只保存長度在4000以內(nèi)的數(shù)據(jù),這樣使用varchar2足矣,所以該方法淘汰。

二、使用CLOB類型來操作。XMLType是繼承了CLOB的存在,所以是可以通過CLOB來操作的。方法是在客戶端創(chuàng)建好CLOB數(shù)據(jù)后傳入數(shù)據(jù)庫通過Oracle的XMLTYPE()函數(shù)來構(gòu)造XMLType的值:

String sql = "insert into xmltable (XML) values(XMLType(?))"; 
String xmldata = "<label>This is an XML fragment</label>"; 
//通過conn創(chuàng)建CLOB
CLOB tempClob = CLOB.createTemporary(connection, false, CLOB.DURATION_SESSION);
//打開CLOB
tempClob.open(CLOB.MODE_READWRITE);
//獲得writer
Writer clobWriter = tempClob.setCharacterStream(100);
//寫入數(shù)據(jù)
clobWriter.write(xmldata);
//刷新
clobWriter.flush();
//關(guān)閉writer
clobWriter.close();
//關(guān)閉CLOB
tempClob.close();
pst.setObject(1, tempClob);

此方法客戶端和數(shù)據(jù)庫同時承擔(dān)了創(chuàng)建XMLType的任務(wù),因此壓力較平均,也沒有超過長度的問題。但是在實際使用過程中又發(fā)現(xiàn),xml的內(nèi)容頭部不能包含以下信息:

<?xml version="1.0" encoding="UTF-8"?>

否則會拋出異常:

PI names starting with XML are reserved

先不說少了這個在以后處理xml內(nèi)容包含中文時會不會遇到蛋疼的亂碼問題,光是看著就讓人感覺不爽,且需求上也要求保存,沒辦法,這個方法又行不通了。

三、使用Oracle提供的oracle.xdb.XMLType類,客戶端創(chuàng)建XMLType后直接把對象傳給數(shù)據(jù)庫:

Connection conn = ... ;//獲得Connection 
PreparedStatement ps = ...;//獲得PreparedSatement 
String sql = "insert into xmltable (XML) values(?)"; 
String xmldata = "<label>This is an XML fragment</label>"; 
//創(chuàng)建一個XMLType對象 
XMLType xmltype = XMLType.createXML(conn, xmldata); 
ps.setObject(1, xmltype); 
ps.executeUpdate();

此方法將創(chuàng)建XMLType的任務(wù)完全交給了客戶端,因此客戶端的壓力大,數(shù)據(jù)庫壓力小。在實測過程中,需要添加兩個jar包,不然會報找不到類的錯誤:

xdb.jar
xmlparserv2.jar

需要注意這jar包又沒版本標(biāo)注,很容易弄錯,一開始我下載了個xdb.jar,怎么弄都不對提示找不到某個類,查看之后發(fā)現(xiàn)是屬于oracle更早期版本,重新下載了一個xdb.jar后正常。
以上三種方法通過插入20萬條數(shù)據(jù)測試比較發(fā)現(xiàn):

第一種方法:耗時最短,服務(wù)器cpu消耗最大;
第二種方法:耗時最長,服務(wù)器cpu消耗居中;
第三種方法:耗時居中,服務(wù)器cpu消耗最小.
 
至此,jdbc操作XMLType類型數(shù)據(jù)終于算是小小的搞定了,不用說采用了第三種方案,但是項目中基本都不會直接用jdbc來操作,像當(dāng)前項目中就采用了Mybatis,上面也講到了使用Mybatis總是出現(xiàn)異常,查看了下Mybatis也沒有對XMLType的實現(xiàn),看來還有的折騰,不過jdbc已經(jīng)搞定,思路已經(jīng)清晰了不是?


Mybatis
使用Mybatis操作XMLType,我們同樣在Java端映射為String類型,當(dāng)直接操作不做任何處理時,和jdbc大體一樣,傳輸?shù)膬?nèi)容長度小于4000時一切正常,當(dāng)傳輸?shù)膬?nèi)容長度超過4000左右時,同樣拋出異常:

ORA-01461: can bind a LONG value only for insert into a LONG column

可見,Mybatis的操作其實和jdbc是一樣的,只不過它在jdbc的外面又封裝了一層,使得我們可以采用配置文件等映射的方式來更方便的訪問數(shù)據(jù)庫,我們要做的,就是在原有Mybatis便捷性的基礎(chǔ)上實現(xiàn)對XMLType類型數(shù)據(jù)的插入,這種情況下,實現(xiàn)一個XMLType類型的自定義TypeHandler處理器是最好的選擇。

這里,我們?nèi)匀徊捎们懊嫣岬降姆桨溉?,自然那兩個jar包:xdb.jar,xmlparserv2.jar也是要加入的。

添加一個XmltypeTypeHandler,實現(xiàn)TypeHandler接口,由于插入數(shù)據(jù)主要用到setParameter方法,所以這里只列出該方法,其它方法代碼略:

/**
 * oracle SYS.XMLTYPE 類型自定義處理器
 */
public class XmltypeTypeHandler implements TypeHandler<String> {
 @Override
 public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
 }
 ...
}

這個setParameter方法就是Mybatis在把數(shù)據(jù)插入到數(shù)據(jù)庫時用來設(shè)置參數(shù)的,至于這個方法的參數(shù)相信你看代碼也已經(jīng)明白了,我們按照前面jdbc的實現(xiàn)方式,在這里插入如下代碼:

public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
 XMLType xmltype = XMLType.createXML(ps.getConnection(), parameter);
 ps.setObject(i,xmltype);
}

并在mapper-config.xml中注冊轉(zhuǎn)換器,因為Mybatis定義的枚舉org.apache.ibatis.type.JdbcType中,沒有我們需要的XMLType類型,在這里我們定義為UNDEFINED:

<configuration>
 <typeHandlers>
  <typeHandler javaType="string" jdbcType="UNDEFINED" handler="com.tyyd.dw.context.XmltypeTypeHandler"/>
 </typeHandlers>
</configuration>

在配置文件參數(shù)中,使用我們的定義的轉(zhuǎn)換器,這樣Mybatis就能找到了:

#{xmlFile,jdbcType=UNDEFINED},

當(dāng)然你也可以更規(guī)范一點,完整的寫出它的類型和使用的轉(zhuǎn)換器:

#{xmlFile,javaType=string,jdbcType=UNDEFINED,typeHandler=com.tyyd.dw.context.XmltypeTypeHandler},
完成上面的步驟,照理說一切都大功告成了,我們來運行一下。

結(jié)果拋出了異常:java.lang.ClassCastException: org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection

不能轉(zhuǎn)換為Oracle的連接對象OracleConnection,查看一下,發(fā)現(xiàn)我們數(shù)據(jù)源使用的是apache的dbcp,應(yīng)該是兩者不兼容吧。網(wǎng)上查了一下,有位仁兄說是給了個完美解決文案,就是在setParameter方法內(nèi)再獨自加載一個Oracle的驅(qū)動類來創(chuàng)建一個connection,如下:

Class.forName("oracle.jdbc.OracleDriver");
Connection connection = DriverManager.getConnection(url, username, password);

這個確實能100%解決連接對象不能轉(zhuǎn)換的問題,但是實現(xiàn)方式上,呵呵,還是不做評論了。還有網(wǎng)上在傳來傳去的,說是可以轉(zhuǎn)換成PoolableConnection 對象,再使用getDelegate方法可以獲得原始代理鏈接,這個貌似可行,我們來試試:

PoolableConnection connection = (PoolableConnection )ps.getConnection();
XMLType xmltype = XMLType.createXML(connection.getDelegate(), parameter);
ps.setObject(i,xmltype);

結(jié)果又拋出了異常:

org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection,不能轉(zhuǎn)換。

沒辦法,看來網(wǎng)上傳來傳去的文章不怎么可靠,沒捷徑了還是自己看看源代碼吧。

通過查看源代碼,我們發(fā)現(xiàn)PoolableConnection繼承了DelegatingConnection類,而DelegatingConnection類實現(xiàn)了Connection接口,我們把它轉(zhuǎn)換成DelegatingConnection試試:

DelegatingConnection connection = (DelegatingConnection )ps.getConnection();
XMLType xmltype = XMLType.createXML(connection.getDelegate(), parameter);
ps.setObject(i,xmltype);

結(jié)果又拋出異常:無法構(gòu)造描述符: Invalid arguments; nested exception is java.sql.SQLException: 無法構(gòu)造描述符: Invalid arguments,通過斷點調(diào)試,發(fā)現(xiàn)connection對象居然是null,怎么會是null呢,網(wǎng)上人家都用的好好的,到我這里就都不行了,真是蛋疼,這不會無解吧,難道真要像上面那位仁兄說的獨自加載一個驅(qū)動類?沒辦法,再研究研究吧。

最后發(fā)現(xiàn),通過getMetaData方法可以獲取它的原始代理連接,柳暗花明啊,趕緊寫上測試,終于正常了,不容易啊,最終代碼如下:

@Override
public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
                       throws SQLException {
 DelegatingConnection connection = (DelegatingConnection) ps.getConnection().getMetaData()
  .getConnection();
 XMLType xmltype = XMLType.createXML(connection.getDelegate(), parameter);
 ps.setObject(i, xmltype);
}

至此,使用Mybatis操作XMLType類型終于是搞定了,過程是一波三折啊。數(shù)據(jù)有插入當(dāng)然要有查詢,接下來就要實現(xiàn)XMLType類型的查詢操作了。

相關(guān)文章

  • 淺談java中異步多線程超時導(dǎo)致的服務(wù)異常

    淺談java中異步多線程超時導(dǎo)致的服務(wù)異常

    下面小編就為大家?guī)硪黄獪\談java中異步多線程超時導(dǎo)致的服務(wù)異常。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • Java實現(xiàn)優(yōu)雅的參數(shù)校驗方法詳解

    Java實現(xiàn)優(yōu)雅的參數(shù)校驗方法詳解

    這篇文章主要為大家詳細(xì)介紹了Java語言如何實現(xiàn)優(yōu)雅的參數(shù)校驗,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定是幫助,需要的可以參考一下
    2022-06-06
  • Mybatis中xml的動態(tài)sql實現(xiàn)示例

    Mybatis中xml的動態(tài)sql實現(xiàn)示例

    本文主要介紹了Mybatis中xml的動態(tài)sql實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Java輕松使用工具類實現(xiàn)獲取wav時間長度

    Java輕松使用工具類實現(xiàn)獲取wav時間長度

    在Java中,工具類定義了一組公共方法,這篇文章將介紹Java中使用工具類來獲取一個wav文件的時間長度,感興趣的同學(xué)繼續(xù)往下閱讀吧
    2021-10-10
  • Java 中利用泛型和反射機(jī)制抽象DAO的實例

    Java 中利用泛型和反射機(jī)制抽象DAO的實例

    這篇文章主要介紹了Java 中利用泛型和反射機(jī)制抽象DAO的實例的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • 淺談PrintStream和PrintWriter的區(qū)別和聯(lián)系

    淺談PrintStream和PrintWriter的區(qū)別和聯(lián)系

    這篇文章主要介紹了淺談PrintStream和PrintWriter的區(qū)別和聯(lián)系,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • SpringBoot中的HATEOAS詳情

    SpringBoot中的HATEOAS詳情

    這篇文章主要介紹了SpringBoot中的HATEOAS詳情,SpringBoot提供了HATEOAS的便捷使用方式,文章圍繞主題展開詳細(xì)介紹內(nèi)容,需要的小伙伴可以參考一下
    2022-05-05
  • 使用Java實現(xiàn)驗證碼程序

    使用Java實現(xiàn)驗證碼程序

    這篇文章主要為大家詳細(xì)介紹了使用Java實現(xiàn)驗證碼程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Java正確使用訪問修飾符的姿勢

    Java正確使用訪問修飾符的姿勢

    訪問修飾符是Java語法中很基礎(chǔ)的一部分,但是能正確的使用Java訪問修飾符的程序員只在少數(shù),下面這篇文章主要給大家介紹了關(guān)于Java正確使用訪問修飾符的姿勢,需要的朋友可以參考下
    2021-11-11
  • 解析Java按值傳遞還是按引用傳遞

    解析Java按值傳遞還是按引用傳遞

    這篇文章主要介紹了解析Java按值傳遞還是按引用傳遞,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01

最新評論