我正在运行 Oracle 11.2.0.3 并试图创建一个映射 XMLType 或 SQLXML 列的可行 UserType。
XMLType 值是 LOB 值,因此它们必须在 Connection.close() 之前为 free() ,否则它们将在 Java 中泄漏数据库资源和堆内存。
从这些列中获取的 XML 值是连接对象;除非它们是通过深层副本复制的,否则它们会在连接关闭后消失。
因此,我在底部编写了这些类来存储 XMLType 对象。
我的问题是——因为这些是 LOB 值,所以必须在事务提交之后、但在连接关闭之前释放它们。有没有办法让 Hibernate UserType 做到这一点?暂时忽略这是一个 SQLXML 对象的事实 - 如果它是 BLOB 或 CLOB,并且我有相同的要求(有人必须在提交之后但在 close() 之前调用 free()),我会怎么做它?
感谢您阅读所有这些...
package com.mycomp.types;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import oracle.xdb.XMLType;
import oracle.xml.binxml.BinXMLDecoder;
import oracle.xml.binxml.BinXMLException;
import oracle.xml.binxml.BinXMLStream;
import oracle.xml.jaxp.JXSAXTransformerFactory;
import oracle.xml.jaxp.JXTransformer;
import oracle.xml.parser.v2.XMLDOMImplementation;
import oracle.xml.parser.v2.XMLDocument;
import oracle.xml.scalable.InfosetReader;
import org.apache.commons.lang.ObjectUtils;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import org.w3c.dom.DOMException;
/**
* This class encapsulates the XMLDocument class into a database XMLType.
* It is used to allow Hibernate entities to use XMLDocument transparently
* for persistence as XMLTypes in an Oracle database.
*
* @author bmarke
*
*/
public class HibernateXMLType implements UserType
{
private static final String CAST_EXCEPTION_TEXT = " cannot be cast to a oracle.xml.parser.v2.XMLDocument.";
@Override
public int[] sqlTypes()
{
return new int[] { Types.SQLXML };
}
@Override
public Class<?> returnedClass()
{
return XMLDocument.class;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException
{
if (x == y)
{
return true;
}
if (!(x instanceof XMLDocument && y instanceof XMLDocument))
{
throw new HibernateException(x.getClass().toString()
+ CAST_EXCEPTION_TEXT);
}
return ObjectUtils.equals(x, y);
}
@Override
public int hashCode(Object x) throws HibernateException
{
if (!(x instanceof XMLDocument))
{
throw new HibernateException(x.getClass().toString()
+ CAST_EXCEPTION_TEXT);
}
return x.hashCode();
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException
{
XMLType xmlData = (XMLType) rs.getSQLXML(names[0]);
XMLDocument doc = null;
XMLDocument toReturn = null;
BinXMLStream stream = null;
InfosetReader reader = null;
if (xmlData == null)
{
doc = null;
toReturn = null;
}
else
{
try
{
stream = xmlData.getBinXMLStream();
BinXMLDecoder decoder = stream.getDecoder();
reader = decoder.getReader();
XMLDOMImplementation domImpl = new XMLDOMImplementation();
domImpl.setAttribute(XMLDocument.SCALABLE_DOM, true);
domImpl.setAttribute(XMLDocument.ACCESS_MODE,
XMLDocument.UPDATEABLE);
doc = (XMLDocument) domImpl.createDocument(reader);
toReturn = (XMLDocument)deepCopy(doc);
}
catch (IllegalArgumentException e)
{
throw new HibernateException(e);
}
catch (DOMException e)
{
throw new HibernateException(e);
}
catch (BinXMLException e)
{
throw new HibernateException(e);
}
finally
{
if(doc != null)
{
doc.freeNode();
}
if(reader != null)
{
reader.close();
}
if(stream != null)
{
stream.close();
}
if(xmlData != null)
{
xmlData.close();
}
}
}
return toReturn;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException
{
if( value == null )
{
st.setNull(index, Types.SQLXML);
}
else if( !(value instanceof XMLDocument) )
{
throw new HibernateException(value.getClass().toString()
+ CAST_EXCEPTION_TEXT);
}
else
{
XMLDocument xml = (XMLDocument) value;
XMLType xmlData = null;
try
{
xmlData = new XMLType(st.getConnection().getMetaData().getConnection(), xml);
st.setSQLXML(index, xmlData);
}
finally
{
if(xmlData != null)
{
xmlData.close();
}
}
}
}
@Override
public Object deepCopy(Object value) throws HibernateException
{
XMLDocument orig = (XMLDocument)value;
DOMResult result;
try
{
JXSAXTransformerFactory tfactory = new oracle.xml.jaxp.JXSAXTransformerFactory();
JXTransformer tx = (JXTransformer)tfactory.newTransformer();
DOMSource source = new DOMSource(orig);
result = new DOMResult();
tx.transform(source,result);
return (XMLDocument)result.getNode();
}
catch (Exception e)
{
throw new HibernateException(e);
}
}
@Override
public boolean isMutable()
{
return true;
}
@Override
public Serializable disassemble(Object value) throws HibernateException
{
XMLDocument doc = (XMLDocument) deepCopy(value);
return doc;
}
@Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException
{
XMLDocument doc = (XMLDocument) deepCopy(cached);
return doc;
}
@Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException
{
return deepCopy(original);
}
}
(是的,以上是 Oracle 特定的......对于那些寻找与 DBMS 无关的类的人,它看起来像这样,但请注意警告,我还没有测试过):
package com.mycomp.types;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Types;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import org.apache.commons.lang.ObjectUtils;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
/**
* This class encapsulates the XMLDocument class into a database XMLType.
* It is used to allow Hibernate entities to use XMLDocument transparently
* for persistence as XMLTypes in an Oracle database.
*
* @author bmarke
*
*/
public class HibernateSQLXML implements UserType
{
private static final String CAST_EXCEPTION_TEXT = " cannot be cast to a oracle.xml.parser.v2.XMLDocument.";
@Override
public int[] sqlTypes()
{
return new int[] { Types.SQLXML };
}
@Override
public Class<?> returnedClass()
{
return SQLXML.class;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException
{
if (x == y)
{
return true;
}
if (!(x instanceof SQLXML && y instanceof SQLXML))
{
throw new HibernateException(x.getClass().toString()
+ CAST_EXCEPTION_TEXT);
}
return ObjectUtils.equals(x, y);
}
@Override
public int hashCode(Object x) throws HibernateException
{
if (!(x instanceof SQLXML))
{
throw new HibernateException(x.getClass().toString()
+ CAST_EXCEPTION_TEXT);
}
return x.hashCode();
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner)
throws HibernateException, SQLException
{
SQLXML xmlData = rs.getSQLXML(names[0]);
Document toReturn = null;
if (xmlData == null)
{
toReturn = null;
}
else
{
try
{
DOMSource source = xmlData.getSource(DOMSource.class);
toReturn = (Document)deepCopy(source);
}
catch (IllegalArgumentException e)
{
throw new HibernateException(e);
}
catch (DOMException e)
{
throw new HibernateException(e);
}
finally
{
if(xmlData != null)
{
xmlData.free();
}
}
}
return toReturn;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException
{
if( value == null )
{
st.setNull(index, Types.SQLXML);
}
else if( !(value instanceof Document) )
{
throw new HibernateException(value.getClass().toString()
+ CAST_EXCEPTION_TEXT);
}
else
{
Document xml = (Document) value;
SQLXML xmlData = null;
try
{
xmlData = st.getConnection().createSQLXML();
DOMResult res = xmlData.setResult(DOMResult.class);
res.setNode(xml);
st.setSQLXML(index, xmlData);
}
finally
{
if(xmlData != null)
{
xmlData.free();
}
}
}
}
public Object deepCopy(DOMSource orig) throws HibernateException
{
DOMResult result;
try
{
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer tx = tfactory.newTransformer();
result = new DOMResult();
tx.transform(orig,result);
return (Document)result.getNode();
}
catch (Exception e)
{
throw new HibernateException(e);
}
}
@Override
public Object deepCopy(Object value) throws HibernateException
{
Document orig = (Document)value;
DOMResult result;
try
{
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer tx = tfactory.newTransformer();
DOMSource source = new DOMSource(orig);
result = new DOMResult();
tx.transform(source,result);
return (Document)result.getNode();
}
catch (Exception e)
{
throw new HibernateException(e);
}
}
@Override
public boolean isMutable()
{
return true;
}
@Override
public Serializable disassemble(Object value) throws HibernateException
{
//NOTE: We're making a really ugly assumption here, that the particular parser
//impelementation creates a Document object that is Serializable. In the case
//of the Oracle XDK parser, it is, but it may not be for the default Xerces
//implementation - you have been warned.
Serializable doc = (Serializable) deepCopy(value);
return doc;
}
@Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException
{
Document doc = (Document) deepCopy(cached);
return doc;
}
@Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException
{
return deepCopy(original);
}
}