最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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的強大存在,可以用來存儲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)文章

  • SpringBoot項目啟動報錯"找不到或無法加載主類"的解決方法

    SpringBoot項目啟動報錯"找不到或無法加載主類"的解決方法

    在使用 IntelliJ IDEA 開發(fā)基于 Spring Boot 框架的 Java 程序時,可能會出現(xiàn)找不到或無法加載主類 com.example.springboot.SpringbootApplication的錯誤提示,下面我們來看看如何解決吧
    2025-03-03
  • Java實現(xiàn)Redis哨兵的示例代碼

    Java實現(xiàn)Redis哨兵的示例代碼

    這篇文章主要介紹了Java實現(xiàn)Redis哨兵的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java結(jié)合uniapp實現(xiàn)驗證碼功能的示例詳解

    Java結(jié)合uniapp實現(xiàn)驗證碼功能的示例詳解

    UniApp 是一個基于 Vue.js 的跨平臺應(yīng)用開發(fā)框架,允許開發(fā)者使用統(tǒng)一的代碼庫來構(gòu)建多平臺應(yīng)用,這篇文章將給大家介紹Java結(jié)合uniapp實現(xiàn)驗證碼功能,文中通過詳細(xì)的代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • Java中的transient關(guān)鍵字解析

    Java中的transient關(guān)鍵字解析

    這篇文章主要介紹了Java中的 transient關(guān)鍵字解析,有時候我們的一些敏感信息比如密碼并不想序列化傳輸給對方,這個時候transient關(guān)鍵字就派上用場了,如果一個類的變量加上了transient關(guān)鍵字那么這個字段就不會被序列化,需要的朋友可以參考下
    2023-09-09
  • 淺談HTTP使用BASIC認(rèn)證的原理及實現(xiàn)方法

    淺談HTTP使用BASIC認(rèn)證的原理及實現(xiàn)方法

    下面小編就為大家?guī)硪黄獪\談HTTP使用BASIC認(rèn)證的原理及實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • Nacos配置中心的配置文件的匹配規(guī)則及說明

    Nacos配置中心的配置文件的匹配規(guī)則及說明

    這篇文章主要介紹了Nacos配置中心的配置文件的匹配規(guī)則及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • SpringCloud3.x集成BigQuery的代碼實現(xiàn)

    SpringCloud3.x集成BigQuery的代碼實現(xiàn)

    Google BigQuery 是一種高性能、可應(yīng)用于大數(shù)據(jù)分析的公主云數(shù)據(jù)庫服務(wù),Spring Cloud 提供了完善的工具和核心功能,可以進行泛動分布應(yīng)用構(gòu)建,本文給大家介紹了SpringCloud3.x集成BigQuery的代碼實現(xiàn),需要的朋友可以參考下
    2025-01-01
  • JavaWeb項目中JSP訪問的問題解決

    JavaWeb項目中JSP訪問的問題解決

    JSP文件一般有兩個存放位置,本文主要介紹了JavaWeb項目中JSP訪問的問題解決,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Java多線程中的ThreadPoolExecutor解讀

    Java多線程中的ThreadPoolExecutor解讀

    這篇文章主要介紹了Java多線程中的ThreadPoolExecutor解讀,線程池中的核心線程數(shù),當(dāng)提交一個任務(wù)時,線程池創(chuàng)建一個新線程執(zhí)行任務(wù),直到當(dāng)前線程數(shù)等于corePoolSize;如果當(dāng)前線程數(shù)為corePoolSize,繼續(xù)提交的任務(wù)被保存到阻塞隊列中,等待被執(zhí)行,需要的朋友可以參考下
    2023-09-09
  • SpringMVC實現(xiàn)數(shù)據(jù)綁定及表單標(biāo)簽

    SpringMVC實現(xiàn)數(shù)據(jù)綁定及表單標(biāo)簽

    這篇文章主要為大家詳細(xì)介紹了SpringMVC實現(xiàn)數(shù)據(jù)綁定及表單標(biāo)簽的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03

最新評論

潞西市| 稻城县| 黄石市| 曲麻莱县| 邵武市| 颍上县| 左权县| 新沂市| 天水市| 云阳县| 长子县| 公安县| 阿坝县| 达日县| 普陀区| 岑溪市| 同江市| 东海县| 措勤县| 嘉峪关市| 南充市| 威信县| 白山市| 江阴市| 高唐县| 邵阳市| 万源市| 揭东县| 汉川市| 滕州市| 宜都市| 孟津县| 三门县| 阿尔山市| 神池县| 五峰| 宣化县| 拜城县| 万山特区| 安阳县| 和林格尔县|