二、Oracle XMLType
引用Oracle官網(wǎng)對于Oracle的XMLType的部分解釋
XMLType is a system-defined opaque type for handling XML data. It as predefined member functions on it to extract XML nodes and fragments.
You can create columns of XMLType and insert XML documents into it. You can also generate XML documents as XMLType instances dynamically using the SYS_XMLGEN and SYS_XMLAGG SQL functions.
三、Hibernate映射Oracle XMLType
Hibernate可以映射Oracle 的 XMLType,默認的是String類型,也可以改成Text類型。
如下所示,字段STORAGE_DETAIL_XML是一個Oracle的XMLType類型字段,Hibernate映射的時候自動映射成String
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <!--
- Mapping file autogenerated by MyEclipse Persistence Tools
- -->
- <hibernate-mapping>
- <class name="com.CDSS.main.model.DatasourceStorage" table="DATASOURCE_STORAGE" schema="DBCDSS">
- <id name="storageId" type="java.lang.Long">
- <column name="STORAGE_ID" precision="22" scale="0" />
- <generator class="native">
- <param name="sequence">SEQUENCE_DSS</param>
- </generator>
- </id>
- <property name="dsId" type="java.lang.Long">
- <column name="DS_ID" precision="22" scale="0" />
- </property>
- <property name="storageDetailXml" type="java.lang.String">
- <column name="STORAGE_DETAIL_XML" />
- </property>
- <property name="isReged" type="java.lang.String">
- <column name="IS_REGED" />
- </property>
- </class>
- </hibernate-mapping>
四、問題原由
Hibernate可以映射Oracle 的 XMLType,默認的是String類型,其實正常情況下沒有多少問題,但是XMLType是一個繼承了blob的強大存在,應該可以存儲2G的數(shù)據(jù),可以如果你按照clob來進行處理的話,Hibernate就會報錯。
引用我在BBS上發(fā)布的問題貼,到現(xiàn)在還是沒有人能解決。(傷心中.....)
4.1、在使用 ***DAO.save(*) 或者 ***DAO.merge(*)的時候會出現(xiàn)問題。問題原因我也知道
4.2、當字段dssXMLInfo的數(shù)據(jù)大小在4000字符以下的時候,可以正常保存或者merge
4.3、當字段dssXMLInfo的數(shù)據(jù)超過4000字符的時候,直接報【Long列插入Long值】類似的錯誤
4.4、參考網(wǎng)上知道,當String的字符超過4000的時候,Hibernate會自動把String轉換成Long類型,網(wǎng)上的建議是把varchar改成clob或者blob【此法不通,不符合我的要求】
4.5、參考網(wǎng)上知道,Hibernate處理Oracle的xmlType的時候,多數(shù)自定義一個映射數(shù)據(jù)類型,然后把hibernate配置文件中的type="String" 換成對應的 type="類的包名"【參考URL:廣東精鷹軟件工作室(劉正仁)http://blog.csdn.net/wmbb/article/details/1045742】
但是這個需要引入3個包,分別是xmlparserv2.jar 、xdb.jar和nls_charset12.jar,這三個包和我現(xiàn)有的weblogic自帶包、Java環(huán)境(使用Weblogic自帶的jdk1.6)發(fā)生沖突,啟動會報【XML解析錯】的錯誤。
之前的項目中也使用這個方法解決問題的,但是部署系統(tǒng)的時候需要先把這幾個包刪除了才可以啟動,非常的不方便,而且操作十分麻煩?!竟识艞壛恕?br>4.6、今天又做了一次嘗試,直接使用sql語句,使用hibernate的sql數(shù)據(jù)提交。問題同樣也是字符超長,無法執(zhí)行?!緡L試了一晚上,沒有成功,故而崩潰】
上面描述的其實是一個問題,當數(shù)據(jù)超過4000字符的時候,直接報【Long列插入Long值】類似的錯誤。這個問題是Hibernate看見更新String類型數(shù)據(jù),哇塞好大,那么就給你轉成Long吧。很腦抽的現(xiàn)象.....糾結了好久。
五、解決方案
Hibernate映射Oracle XMLType在網(wǎng)上有諸多版本,但是這些版本要不是Oracle版本較低(Oracle 9i),要不是Hibernate版本過高(Hibernate4),還有就是不是為Weblogic考慮的(使用jboss、tomcat等),因此拿過來很多東西都是錯誤的。
參考網(wǎng)上諸多解決方案,經(jīng)過好幾天的測試、處理,終于找打一個這中的解決方案,測試通過。(只針對第一章所講的環(huán)境,其它未測試)
5.1 系統(tǒng)添加幾個jar包
(1)ojdbc6_g.jar(從Oracle11g安裝目錄中找)【部署后刪除,weblogic自帶此包,項目中使用是因為需要相關的驅動】
(2)xmlparserv2.jar(從Oracle11g安裝目錄中找)【部署后刪除,此文件和其它jar沖突,原因未知,啟動成功后建議還原】
(3)xdb.jar(從網(wǎng)上下載)
(4)weblogic.jar(從weblogic安裝路徑下找)【部署后刪除,weblogic自帶此包,項目中使用是因為需要相關的驅動】
5.2 新建自定義的OracleType,繼承UserType, Serializable。
- package com.***.util.XMLHandle;
-
- import java.io.Serializable;
- import java.sql.Connection;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
-
- import oracle.sql.OPAQUE;
- import oracle.xdb.XMLType;
-
- import org.hibernate.HibernateException;
- import org.hibernate.usertype.UserType;
-
- import weblogic.jdbc.wrapper.PoolConnection;
-
- @SuppressWarnings("rawtypes")
- public class OracleXMLType implements UserType, Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- private static final Class returnedClass = String.class;
- private static final int[] SQL_TYPES = new int[] { oracle.xdb.XMLType._SQL_TYPECODE };
-
- public int[] sqlTypes() {
- return SQL_TYPES;
- }
-
- public Class returnedClass() {
- return returnedClass;
- }
-
- public boolean equals(Object arg0, Object arg1) throws HibernateException {
- if (arg0 == null || arg1 == null) {
- throw new HibernateException("None of the arguments can be null.");
- }
- if (arg0 instanceof oracle.xdb.XMLType
- && arg1 instanceof oracle.xdb.XMLType) {
- return arg0.equals(arg1);
- }
- return false;
- }
-
- public int hashCode(Object arg0) throws HibernateException {
- return 0;
- }
-
- public Object nullSafeGet(ResultSet rs, String[] names, Object arg2)
- throws HibernateException, SQLException {
-
- OPAQUE op = (OPAQUE) rs.getObject(names[0]);
- oracle.xdb.XMLType xt = oracle.xdb.XMLType.createXML(op);
- return xt.getStringVal();
- }
-
- public void nullSafeSet(PreparedStatement st, Object value, int index)
- throws HibernateException, SQLException {
-
- Connection conn = ((PoolConnection) st.getConnection())
- .getVendorConnection();
-
- OPAQUE aClob = XMLType.createXML(conn, (String) value);
- // XMLType aClob = XMLType.createXML(conn, (String) value);
- st.setObject(index, aClob);
-
- }
-
- public Object deepCopy(Object value) throws HibernateException {
- return value;
- }
-
- public boolean isMutable() {
- return false;
- }
-
- public Serializable disassemble(Object arg0) throws HibernateException {
- return null;
- }
-
- public Object assemble(Serializable arg0, Object arg1)
- throws HibernateException {
- return null;
- }
-
- public Object replace(Object arg0, Object arg1, Object arg2)
- throws HibernateException {
- return null;
- }
- }
5.3 修改Hibernate映射文件,把type="string"換成type="com.CDSS.util.XMLHandle.OracleXMLType"【你定義的類】
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <!--
- Mapping file autogenerated by MyEclipse Persistence Tools
- -->
- <hibernate-mapping>
- <class name="com.CDSS.main.model.DatasourceStorage" table="DATASOURCE_STORAGE" schema="DBCDSS">
- <id name="storageId" type="java.lang.Long">
- <column name="STORAGE_ID" precision="22" scale="0" />
- <generator class="native">
- <param name="sequence">SEQUENCE_DSS</param>
- </generator>
- </id>
- <property name="dsId" type="java.lang.Long">
- <column name="DS_ID" precision="22" scale="0" />
- </property>
- <property name="storageDetailXml" type="com.CDSS.util.XMLHandle.OracleXMLType">
- <column name="STORAGE_DETAIL_XML" />
- </property>
- <property name="isReged" type="java.lang.String">
- <column name="IS_REGED" />
- </property>
- </class>
- </hibernate-mapping>
5.4、其它不變,然后部署,啟動之前刪除前面提到的沖突包。此時就可以直接使用Hibernate自帶的Merge或者save或者update進行更新數(shù)據(jù)超過4000的信息了。
六、后感
Hibernate還是需要繼續(xù)努力的!