国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java使用JDBC或MyBatis框架向Oracle中插入XMLType數據

Java使用JDBC或MyBatis框架向Oracle中插入XMLType數據

2020-05-24 12:08碼農的士首席的哥隊長 JAVA教程

XMLType是Oracle支持的一種基于XML格式存儲的數據類型,這里我們共同來探究Java使用JDBC或MyBatis框架向Oracle中插入XMLType數據的方法:

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

JDBC
在折騰了半天之后,發現jdbc操作主要有3種方法:
一、在Java中把XMLType當作字符串String來用,具體創建XMLType的任務完全交給數據庫:

?
1
2
3
4
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();

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String sql = "insert into xmltable (XML) values(XMLType(?))";
String xmldata = "<label>This is an XML fragment</label>";
//通過conn創建CLOB
CLOB tempClob = CLOB.createTemporary(connection, false, CLOB.DURATION_SESSION);
//打開CLOB
tempClob.open(CLOB.MODE_READWRITE);
//獲得writer
Writer clobWriter = tempClob.setCharacterStream(100);
//寫入數據
clobWriter.write(xmldata);
//刷新
clobWriter.flush();
//關閉writer
clobWriter.close();
//關閉CLOB
tempClob.close();
pst.setObject(1, tempClob);

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

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

否則會拋出異常:

?
1
PI names starting with XML are reserved

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

三、使用Oracle提供的oracle.xdb.XMLType類,客戶端創建XMLType后直接把對象傳給數據庫:

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

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

?
1
2
xdb.jar
xmlparserv2.jar

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

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


Mybatis
使用Mybatis操作XMLType,我們同樣在Java端映射為String類型,當直接操作不做任何處理時,和jdbc大體一樣,傳輸的內容長度小于4000時一切正常,當傳輸的內容長度超過4000左右時,同樣拋出異常:

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

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

這里,我們仍然采用前面提到的方案三,自然那兩個jar包:xdb.jar,xmlparserv2.jar也是要加入的。

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

?
1
2
3
4
5
6
7
8
9
/**
 * 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在把數據插入到數據庫時用來設置參數的,至于這個方法的參數相信你看代碼也已經明白了,我們按照前面jdbc的實現方式,在這里插入如下代碼:

?
1
2
3
4
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中注冊轉換器,因為Mybatis定義的枚舉org.apache.ibatis.type.JdbcType中,沒有我們需要的XMLType類型,在這里我們定義為UNDEFINED:

?
1
2
3
4
5
<configuration>
 <typeHandlers>
  <typeHandler javaType="string" jdbcType="UNDEFINED" handler="com.tyyd.dw.context.XmltypeTypeHandler"/>
 </typeHandlers>
</configuration>

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

?
1
#{xmlFile,jdbcType=UNDEFINED},

當然你也可以更規范一點,完整的寫出它的類型和使用的轉換器:

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

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

不能轉換為Oracle的連接對象OracleConnection,查看一下,發現我們數據源使用的是apache的dbcp,應該是兩者不兼容吧。網上查了一下,有位仁兄說是給了個完美解決文案,就是在setParameter方法內再獨自加載一個Oracle的驅動類來創建一個connection,如下:

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

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

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

結果又拋出了異常:

org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to org.apache.commons.dbcp.PoolableConnection,不能轉換。

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

通過查看源代碼,我們發現PoolableConnection繼承了DelegatingConnection類,而DelegatingConnection類實現了Connection接口,我們把它轉換成DelegatingConnection試試:

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

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

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

?
1
2
3
4
5
6
7
8
@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類型終于是搞定了,過程是一波三折啊。數據有插入當然要有查詢,接下來就要實現XMLType類型的查詢操作了。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美精品国产精品 | 中文字幕av网站 | 91.成人天堂一区 | 国产精品欧美久久久久一区二区 | 国产精品中文字幕在线 | 成人午夜精品一区二区三区 | 国产精品69久久久久水密桃 | 中文字幕一区二区三区在线观看 | 日本人在线观看 | 国产精品一码二码三码在线 | 欧美一级欧美三级在线观看 | 成人午夜视频在线观看 | 国产精品久久久久久久久久新婚 | 日韩av在线中文字幕 | 国产黄色在线网站 | 精品视频久久 | 欧美日韩亚洲视频 | 成a人片在线观看 | 蜜桃一二三区 | av毛片 | 欧美日韩美女 | 久久久精品免费观看 | 天天夜操| 亚洲区在线 | 91精品久久久久久久久 | 欧美一区二区三区精品 | 五月天导航 | 午夜影院网站 | 国产精品成人3p一区二区三区 | 日本不卡在线观看 | 国产在线精品一区 | 日韩欧美不卡 | 亚洲二区在线播放 | av网站免费在线观看 | aaa黄色片| 羞羞网站免费观看 | 黄片毛片免费观看 | 欧美精品成人 | 亚洲国产成人av好男人在线观看 | 国产欧美日韩综合精品一区二区 | 色九九|