解决:Weblogic容器、SSH框架下Hibernate映射Oracle XMLType方法与Jar包冲突

雪影工作室版权所有,转载请注明【http://blog.csdn.net/lina791211】

一、框架背景

      1、开发工具  MyEclipse 10 Pro

      2、框架使用 Struts2.3,Hibernate3,Spring3.0.5 (标准SSH框架)

      3、版本管理 svn 1.6 插件,visual svn 版本管理工具

      4、数 据  库 Oracle 11g R2

二、Oracle XMLType

      引用Oracle官网对于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.



        Oracle XMLType的本质是blob类型,但是Oracle对其做了特殊处理,我们可以直接使用Xquery进行相关的创建、查询、修改等操作,非常的利民。

三、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的数据,可以如果你按照clob来进行处理的话,Hibernate就会报错。

      引用我在BBS上发布的问题贴,到现在还是没有人能解决。(伤心中.....)


4.1、在使用 ***DAO.save(*) 或者 ***DAO.merge(*)的时候会出现问题。问题原因我也知道
4.2、当字段dssXMLInfo的数据大小在4000字符以下的时候,可以正常保存或者merge
4.3、当字段dssXMLInfo的数据超过4000字符的时候,直接报【Long列插入Long值】类似的错误
4.4、参考网上知道,当String的字符超过4000的时候,Hibernate会自动把String转换成Long类型,网上的建议是把varchar改成clob或者blob【此法不通,不符合我的要求】
4.5、参考网上知道,Hibernate处理Oracle的xmlType的时候,多数自定义一个映射数据类型,然后把hibernate配置文件中的type="String" 换成对应的 type="类的包名"【参考URL:广东精鹰软件工作室(刘正仁)http://blog.csdn.net/wmbb/article/details/1045742】
    但是这个需要引入3个包,分别是xmlparserv2.jar 、xdb.jar和nls_charset12.jar,这三个包和我现有的weblogic自带包、Java环境(使用Weblogic自带的jdk1.6)发生冲突,启动会报【XML解析错】的错误。
    之前的项目中也使用这个方法解决问题的,但是部署系统的时候需要先把这几个包删除了才可以启动,非常的不方便,而且操作十分麻烦。【故而放弃了】
4.6、今天又做了一次尝试,直接使用sql语句,使用hibernate的sql数据提交。问题同样也是字符超长,无法执行。【尝试了一晚上,没有成功,故而崩溃】


        上面描述的其实是一个问题,当数据超过4000字符的时候,直接报【Long列插入Long值】类似的错误。这个问题是Hibernate看见更新String类型数据,哇塞好大,那么就给你转成Long吧。很脑抽的现象.....纠结了好久。

五、解决方案

      Hibernate映射Oracle XMLType在网上有诸多版本,但是这些版本要不是Oracle版本较低(Oracle 9i),要不是Hibernate版本过高(Hibernate4),还有就是不是为Weblogic考虑的(使用jboss、tomcat等),因此拿过来很多东西都是错误的。


      参考网上诸多解决方案,经过好几天的测试、处理,终于找打一个这中的解决方案,测试通过。(只针对第一章所讲的环境,其它未测试)


5.1 系统添加几个jar包

(1)ojdbc6_g.jar(从Oracle11g安装目录中找)【部署后删除,weblogic自带此包,项目中使用是因为需要相关的驱动】

(2)xmlparserv2.jar(从Oracle11g安装目录中找)【部署后删除,此文件和其它jar冲突,原因未知,启动成功后建议还原

(3)xdb.jar(从网上下载)

(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进行更新数据超过4000的信息了。

六、后感

      Hibernate还是需要继续努力的!


你可能感兴趣的:(oracle,Hibernate,weblogic,ssh,xmltype)