使用Hibernate4处理Oracle XmlType字段类型
网上有很多关于使用Hibernate处理Oracle XmlType的文章,但大多数资料都已经过时,不能使用。本人在经过对各种解决办法的测试汇总后,终于能够使用Hibernate4正常存取XmlType类型的字段了,而且解决4000个字符的限制。
使用的技术框架和环境:
- Hibernate 4.3.11
- Oracle 11g
- jdk 1.7
扩展Hibernate的UserType类型
请参考代码
添加Oracle的XmlType类型
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import oracle.xdb.XMLType;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class OracleXmlType implements UserType, Serializable {
private static final long serialVersionUID = 2308230823023l;
private static final Class returnedClass = Document.class;
private static final int[] SQL_TYPES = { oracle.xdb.XMLType._SQL_TYPECODE };
public int[] sqlTypes() {
return SQL_TYPES;
}
public Class returnedClass() {
return returnedClass;
}
public int hashCode(Object _obj) {
return _obj.hashCode();
}
public Object assemble(Serializable _cached, Object _owner)
throws HibernateException {
try {
return OracleXmlType.stringToDom((String) _cached);
} catch (Exception e) {
throw new HibernateException(
"Could not assemble String to Document", e);
}
}
public Serializable disassemble(Object _obj) throws HibernateException {
try {
return OracleXmlType.domToString((Document) _obj);
} catch (Exception e) {
throw new HibernateException(
"Could not disassemble Document to Serializable", e);
}
}
public Object replace(Object _orig, Object _tar, Object _owner) {
return deepCopy(_orig);
}
public boolean equals(Object arg0, Object arg1) throws HibernateException {
if (arg0 == null && arg1 == null)
return true;
else if (arg0 == null && arg1 != null)
return false;
else
return arg0.equals(arg1);
}
public Object deepCopy(Object value) throws HibernateException {
if (value == null)
return null;
return (Document) ((Document) value).cloneNode(true);
}
public boolean isMutable() {
return false;
}
protected static String domToString(Document _document)
throws TransformerException {
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(_document);
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
transformer.transform(source, result);
return sw.toString();
}
protected static Document stringToDom(String xmlSource)
throws SAXException, ParserConfigurationException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(xmlSource
.getBytes("UTF-8")));
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor arg2, Object arg3) throws HibernateException,
SQLException {
XMLType xmlType = (XMLType) rs.getObject(names[0]);
return (xmlType != null) ? xmlType.getDOM() : null;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor arg3) throws HibernateException, SQLException {
OracleNativeExtractor extrator = new OracleNativeExtractor();
Connection nativeConn = extrator
.getNativeConnection(st.getConnection());
try {
XMLType xmlType = null;
if (value != null) {
xmlType = new oracle.xdb.XMLType(nativeConn,
OracleXmlType.domToString((Document) value));
}
st.setObject(index, xmlType);
} catch (Exception e) {
throw new SQLException(
"Could not covert Document to String for storage");
}
}
}
添加处理Connection的类文件
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import oracle.jdbc.driver.OracleConnection;
import com.mchange.v2.c3p0.C3P0ProxyConnection;
public class OracleNativeExtractor {
public static Connection getRawConnection(Connection con) {
return con;
}
public Connection getNativeConnection(Connection con) throws SQLException {
if (con instanceof OracleConnection) {
return con;
}
else if (con instanceof C3P0ProxyConnection) {
C3P0ProxyConnection cpCon = (C3P0ProxyConnection) con;
try {
Method rawConnMethod = getClass().getMethod("getRawConnection",
new Class[] {Connection.class});
return (Connection) cpCon.rawConnectionOperation(
rawConnMethod, null, new Object[] {C3P0ProxyConnection.RAW_CONNECTION});
}
catch (SQLException ex) {
throw ex;
}
catch (Exception ex) {
throw new SQLException("Error in reflection:"+ex.getMessage());
}
}
else {
Connection conTmp = con.getMetaData().getConnection();
if (conTmp instanceof OracleConnection) return conTmp;
}
throw new SQLException("Could not find Native Connection of type OracleConnection");
}
}
添加POJO Bean类,这里使用注解
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
import org.w3c.dom.Document;
@Entity
@Table(name = "TESTXML")
public class Testxml implements java.io.Serializable {
// Fields
private String sid;
private Document xmldata;
// Constructors
/** default constructor */
public Testxml() {
}
/** minimal constructor */
public Testxml(String sid) {
this.sid = sid;
}
/** full constructor */
public Testxml(String sid, Document xmldata) {
this.sid = sid;
this.xmldata = xmldata;
}
// Property accessors
@Id
@Column(name = "SID", unique = true, nullable = false, length = 50)
public String getSid() {
return this.sid;
}
public void setSid(String sid) {
this.sid = sid;
}
@Type(type="OracleXmlType")
@Column(name="XMLDATA", columnDefinition="XMLTYPE")
public Document getXmldata() {
return this.xmldata;
}
public void setXmldata(Document xmldata) {
this.xmldata = xmldata;
}
}
使用到的其他库文件
程序运行中,需要使用到两个Oracle的类库:xdb6.jar和xmlparserv2.jar,这两个文件可以在Oracle的安装目录中找到,建议不要从网上下载,网上下载的文件有些版本较旧,缺少方法体,本人就在这里踩了不少坑。
若有其他问题,欢迎交流,谢谢。