如何清理Hibernate UserType中的LOB值? [英] How do I clean up LOB values in Hibernate UserTypes?

查看:129
本文介绍了如何清理Hibernate UserType中的LOB值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在运行Oracle 11.2.0.3,并试图创建一个映射XMLType或SQLXML列的可用UserType。
$ b Existing 解决方案 在线发现都有两个问题:


  1. XMLType值是LOB值,因此它们必须在Connection.close()之前为free(),否则它们将泄漏数据库资源和Java中的堆内存。

  2. 从这些列中提取的XML值是连接的对象;除非它们通过深层复制进行复制,否则在连接关闭后它们将消失。

  3. 在底部存储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;

    导入oracle.xdb.XMLType;
    import oracle.xml.binxml.BinXMLDecoder;
    import oracle.xml.binxml.BinXMLException;
    导入oracle.xml.binxml.BinXMLStream;
    import oracle.xml.jaxp.JXSAXTransformerFactory;
    导入oracle.xml.jaxp.JXTransformer;
    import oracle.xml.parser.v2.XMLDOMImplementation;
    import oracle.xml.parser.v2.XMLDocument;
    导入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;

    / **
    *该类将XMLDocument类封装到数据库XMLType中。
    *它用于允许Hibernate实体在Oracle数据库中以透明方式使用XMLDocument
    *作为XMLTypes的持久性。
    *
    * @author bmarke
    *
    * /
    public class HibernateXMLType implements UserType
    {
    private static final String CAST_EXCEPTION_TEXT =can not将其转换为oracle.xml.parser.v2.XMLDocument。;

    @Override
    public int [] sqlTypes()
    {
    return new int [] {Types.SQLXML};
    }

    @Override
    public Class<?> returnedClass()
    {
    return XMLDocument.class;

    $ b @Override
    public boolean equals(Object x,Object y)throws HibernateException
    {
    if(x == y)
    {
    返回true;


    if(!(x XML instanceof&& y instanceof XMLDocument的实例))
    {
    throw new HibernateException(x.getClass()。toString( )
    + CAST_EXCEPTION_TEXT);
    }

    return ObjectUtils.equals(x,y);

    $ b @Override
    public int hashCode(Object x)throws HibernateException
    {
    if(!(x instanceof XMLDocument))
    {
    抛出新的HibernateException(x.getClass()。toString()
    + CAST_EXCEPTION_TEXT);
    }

    return x.hashCode();

    $ b @Override
    public Object nullSafeGet(ResultSet rs,String [] names,
    SessionImplementor session,Object owner)
    抛出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)
    {
    抛出新的HibernateException(e);
    }
    catch(DOMException e)
    {
    抛出新的HibernateException(e);
    }
    catch(BinXMLException e)
    {
    抛出新的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;

    $ b @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(!(instanceof XMLDocument))
    {
    throw new HibernateException(value.getClass()。toString()
    + CAST_EXCEPTION_TEXT);
    }
    else
    {
    XMLDocument xml =(XMLDocument)value;
    XMLType xmlData = null;

    尝试
    {
    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)值;

    DOMResult结果;

    尝试
    {
    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)
    {
    抛出新的HibernateException(e);



    @Override
    public boolean isMutable()
    {
    return true;

    $ b @Override
    public Serializable反汇编(Object value)抛出HibernateException
    {
    XMLDocument doc =(XMLDocument)deepCopy(value);

    return doc;

    $ b @Override
    公共对象集合(可序列化缓存,对象所有者)
    抛出HibernateException
    {
    XMLDocument doc =(XMLDocument) deepcopy的(缓存);

    return doc;

    $ b @Override
    public Object replace(Object original,Object target,Object owner)
    throws HibernateException
    {
    return deepCopy(原版的);


    $ / code $ / pre

    (是的,上面是特定于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;

    / **
    *该类将XMLDocument类封装到数据库XMLType中。
    *它用于允许Hibernate实体在Oracle数据库中以透明方式使用XMLDocument
    *作为XMLTypes的持久性。
    *
    * @author bmarke
    *
    * /
    public class HibernateSQLXML implements UserType
    {
    private static final String CAST_EXCEPTION_TEXT =can not将其转换为oracle.xml.parser.v2.XMLDocument。;

    @Override
    public int [] sqlTypes()
    {
    return new int [] {Types.SQLXML};
    }

    @Override
    public Class<?> returnedClass()
    {
    返回SQLXML.class;

    $ b @Override
    public boolean equals(Object x,Object y)throws HibernateException
    {
    if(x == y)
    {
    返回true;


    if(!(x instanceof SQLXML&&& y instanceof SQLXML))
    {
    throw new HibernateException(x.getClass()。toString( )
    + CAST_EXCEPTION_TEXT);
    }

    return ObjectUtils.equals(x,y);

    $ b @Override
    public int hashCode(Object x)throws HibernateException
    {
    if(!(x instanceof SQLXML))
    {
    抛出新的HibernateException(x.getClass()。toString()
    + CAST_EXCEPTION_TEXT);
    }

    return x.hashCode();

    $ b @Override
    public Object nullSafeGet(ResultSet rs,String [] names,
    SessionImplementor session,Object owner)
    抛出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)
    {
    抛出新的HibernateException(e);
    }
    catch(DOMException e)
    {
    抛出新的HibernateException(e);
    }
    finally
    {
    if(xmlData!= null)
    {
    xmlData.free();
    }
    }
    }

    return toReturn;

    $ b @Override
    public void nullSafeSet(PreparedStatement st,Object value,int index,
    SessionImplementor session)throws HibernateException,SQLException
    {
    if(value == null)
    {
    st.setNull(index,Types.SQLXML);

    if(!(value instanceof Document))
    {
    throw new HibernateException(value.getClass()。toString()
    + CAST_EXCEPTION_TEXT);
    }
    else
    {
    Document xml =(Document)value;
    SQLXML xmlData = null;

    尝试
    {
    xmlData = st.getConnection()。createSQLXML();

    DOMResult res = xmlData.setResult(DOMResult.class);

    res.setNode(xml);

    st.setSQLXML(index,xmlData);
    }
    finally
    {
    if(xmlData!= null)
    {
    xmlData.free();




    $ b public Object deepCopy(DOMSource orig)抛出HibernateException
    {
    DOMResult result;

    尝试
    {
    TransformerFactory tfactory = TransformerFactory.newInstance();
    Transformer tx = tfactory.newTransformer();

    result = new DOMResult();
    tx.transform(orig,result);

    return(Document)result.getNode();
    }
    catch(Exception e)
    {
    抛出新的HibernateException(e);


    $ b @Override
    public Object deepCopy(Object value)throws HibernateException
    {
    Document orig =(Document)value;

    DOMResult结果;

    尝试
    {
    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)
    {
    抛出新的HibernateException(e);



    @Override
    public boolean isMutable()
    {
    return true;
    }

    @Override
    public可串行化反汇编(Object value)抛出HibernateException
    {
    //注意:我们在这里做了一个非常丑陋的假设,特定的解析器
    // impelementation将创建一个Serializable的Document对象。在Oracle XDK解析器的
    //的情况下,它是,但它可能不是默认的Xerces
    //实现 - 您已被警告。
    Serializable doc =(Serializable)deepCopy(value);

    return doc;

    $ b @Override
    public Object assemble(Serializable cached,Object owner)
    throws HibernateException
    {
    Document doc =(Document) deepcopy的(缓存);

    return doc;

    $ b @Override
    public Object replace(Object original,Object target,Object owner)
    throws HibernateException
    {
    return deepCopy(原版的);
    }
    }


    解决方案

    I想通过Hibernate有一些方法可以添加一个ActionListener类,在提交完成后可以完成一些工作。有人从freenode的#hibernate房间建议我们尝试使用AfterTransactionCompletionProcess来做我们需要的。



    所以下一个显而易见的问题是......我的例子是哪里?可以使用?我打开了一个SOF问题并自己回答:如何使用org.hibernate .action.spi.AfterTransactionCompletionProcess?



    因此,使用这个例子加上你介绍的 HibernateXMLType 类,我们现在可以注册一个AfterTransactionCompletionProcess进程,以便它被调用以满足您的要求:必须在事务提交后,但在连接关闭之前调用。



    是源代码。



    请参阅我遇到困难的评论。我不知道该从实体中调用什么来手动清除内存。我想知道如何在实体中的 java.sql.SQLXML 对象上调用 free()方法从> doAfterTransactionCompletion 方法...从而消除内存泄漏。



    我会在早上看看我能否弄清楚。也许这就是你需要的解决方案?如果是这样,太棒了!



    HibernateTest.java

      import org.hibernate.Session; 
    import org.hibernate.SessionFactory;
    import org.hibernate.action.spi.AfterTransactionCompletionProcess;
    导入org.hibernate.cfg.Configuration;
    import org.hibernate.engine.spi.SessionImplementor;
    import org.hibernate.event.service.spi.EventListenerRegistry;
    import org.hibernate.event.spi.EventType;
    import org.hibernate.event.spi.PostInsertEvent;
    import org.hibernate.event.spi.PostInsertEventListener;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;

    public class HibernateTest {
    public static void main(String [] args){
    PostInsertTransactionBoundaryListener listener = new PostInsertTransactionBoundaryListener();
    配置配置=新配置();
    configuration.configure();
    ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()。applySettings(configuration.getProperties())。buildServiceRegistry();
    EventListenerRegistry registry = serviceRegistry.getService(EventListenerRegistry.class);
    registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener(listener);
    SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    Session session = sessionFactory.openSession();
    session.getTransaction()。begin();

    TestEntity entity = new TestEntity();
    session.save(entity);
    session.getTransaction()。commit();
    session.close();


    私有静态类PostInsertTransactionBoundaryListener实现PostInsertEventListener {
    private static final long serialVersionUID = 1L;
    public void onPostInsert(final PostInsertEvent event){
    event.getSession()。getActionQueue()。registerProcess(new AfterTransactionCompletionProcess(){
    public void doAfterTransactionCompletion(boolean success,SessionImplementor session){
    TestEntity testEntity =(TestEntity)event.getEntity();
    if(testEntity!= null){
    //如何释放内存以避免内存泄漏???
    }
    }
    });
    }

    }
    }

    TestEntity.java

      import javax.persistence.Entity; 
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;

    @Entity
    @Table(name =TEST)
    public class TestEntity {
    @Id
    @GeneratedValue
    private Integer id ;

    私有HibernateXMLType xml;

    public Integer getId(){
    return id;
    }

    public void setId(Integer id){
    this.id = id;
    }

    public HibernateXMLType getXml(){
    return xml;
    }

    public void setXml(HibernateXMLType xml){
    this.xml = xml;
    }

    }


    I am running Oracle 11.2.0.3 and am attempting to create a workable UserType that maps XMLType or SQLXML columns.

    Existing solutions found online all have two problems:

    1. XMLType values are LOB values, so they must be free() prior to Connection.close() or they will leak both database resources and heap memory in Java.

    2. XML values fetched from these columns are connected objects; unless they are copied via a deep copy, they are gone after the connection closes.

    So, I wrote this classes at the bottom to store XMLType objects.
    My question is this - since these are LOB values, they must be freed after the transaction commits, but before the connection closes. Is there a way to get a Hibernate UserType to do this? Ignore the fact that this is an SQLXML object for a moment - if it were a BLOB or a CLOB, and I had the same requirement (that someone has to call free() after commit but before close()), how would I do it?

    Thank you for reading through all this...

    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);
        }
    }
    

    (Yes, the above is Oracle-specific... for those of you looking for a DBMS-agnostic class, it looks like this, but note the warning, and I haven't tested it):

    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);
        }
    }
    

    解决方案

    I figured Hibernate would have some way to add an ActionListener sort of thing that can do some work after a commit was completed. Someone from the #hibernate room on freenode suggested we try to use a AfterTransactionCompletionProcess to do what we need.

    So the next obvious question is... where is an example I can use? I opened a SOF question and answered it myself: How to use org.hibernate.action.spi.AfterTransactionCompletionProcess?

    So using this example plus the HibernateXMLType class you presented, we can now register an AfterTransactionCompletionProcess process so that it gets called to hopefully meet your requirement: "Must get called after the transaction commits, but before the connection closes."

    Below is the source code.

    Please see the comment where I got kind of stuck. I don't know exactly what to call from the entity to clear the memory manually. I'm wondering how I can call the free() method on the java.sql.SQLXML object in the entity from the doAfterTransactionCompletion method... thus eliminating the memory leak.

    I'll take this back up in the morning and see if I can figure that out. Maybe this is all you need to get the solution? If so, great!

    HibernateTest.java

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.action.spi.AfterTransactionCompletionProcess;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.engine.spi.SessionImplementor;
    import org.hibernate.event.service.spi.EventListenerRegistry;
    import org.hibernate.event.spi.EventType;
    import org.hibernate.event.spi.PostInsertEvent;
    import org.hibernate.event.spi.PostInsertEventListener;
    import org.hibernate.service.ServiceRegistry;
    import org.hibernate.service.ServiceRegistryBuilder;
    
    public class HibernateTest {
        public static void main(String [] args) {
            PostInsertTransactionBoundaryListener listener = new PostInsertTransactionBoundaryListener();
            Configuration configuration = new Configuration();
            configuration.configure();
            ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
            EventListenerRegistry registry = serviceRegistry.getService(EventListenerRegistry.class);
            registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener(listener);
            SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);        
            Session session = sessionFactory.openSession();
            session.getTransaction().begin();
    
            TestEntity entity = new TestEntity();
            session.save(entity);
            session.getTransaction().commit();
            session.close();
    
        }
        private static class PostInsertTransactionBoundaryListener implements PostInsertEventListener {
            private static final long serialVersionUID = 1L;
            public void onPostInsert(final PostInsertEvent event) {
                event.getSession().getActionQueue().registerProcess(new AfterTransactionCompletionProcess() {
                    public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
                        TestEntity testEntity = (TestEntity)event.getEntity();
                        if (testEntity != null) {
                            // How can I free the memory here to avoid the memory leak???
                        }
                    }
                });
            }
    
        }
    }
    

    TestEntity.java

    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Entity
    @Table(name = "TEST")
    public class TestEntity {
        @Id
        @GeneratedValue
        private Integer id;
    
        private HibernateXMLType xml;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public HibernateXMLType getXml() {
            return xml;
        }
    
        public void setXml(HibernateXMLType xml) {
            this.xml = xml;
        }
    
    }
    

    这篇关于如何清理Hibernate UserType中的LOB值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆