0

尝试在 Oracle 11g 数据库中保存大文件时遇到问题,我使用 Spring 和 Hibernate 3.6.9 作为 JPA 实现。

持久化使用Spring,配置如下:

<bean id="entityManagerFactory"
            class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
            <property name="generateDdl" value="false" />
        </bean>
    </property>
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </property>
    <property name="loadTimeWeaver">
        <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.connection.SetBigStringTryClob">true</prop>
            <prop key="hibernate.jdbc.batch_size">0</prop>
            <prop key="hibernate.jdbc.use_streams_for_binary">true</prop>
        </props>
    </property>
</bean>

我要保留的实体包含一个定义如下的列:

@Column(name = "FILE_OBJECT")
@Lob
private byte[] fileObject;
...

我遇到了这个stackTrace:

java.lang.OutOfMemoryError: Java heap space
at java.lang.reflect.Array.newArray(Native Method)
at java.lang.reflect.Array.newInstance(Array.java:52)
at org.hibernate.type.descriptor.java.ArrayMutabilityPlan.deepCopyNotNull(ArrayMutabilityPlan.java:44)
at org.hibernate.type.descriptor.java.MutableMutabilityPlan.deepCopy(MutableMutabilityPlan.java:58)
at org.hibernate.type.AbstractStandardBasicType.deepCopy(AbstractStandardBasicType.java:314)
at org.hibernate.type.AbstractStandardBasicType.deepCopy(AbstractStandardBasicType.java:310)
at org.hibernate.type.TypeHelper.deepCopy(TypeHelper.java:68)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:302)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:143)
at org.hibernate.ejb.event.EJB3MergeEventListener.saveWithGeneratedId(EJB3MergeEventListener.java:62)
at org.hibernate.event.def.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:415)
at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:341)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:258)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:877)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:859)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:279)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:450)
at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:336)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:258)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:877)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:859)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:279)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)

我用谷歌搜索了很多,但没有发现任何帮助,我仍然得到同样的错误,如果有人可以帮忙?一些链接提到使用另一个 Oracle 驱动程序,但正如我在堆栈跟踪中看到的那样,问题出在 Hibernate 代码中,我认为问题与 DB 无关(我使用最新的驱动程序 ojdbc6)。

4

1 回答 1

0

最后,我想我找到了一个解决方案,定义了一个链接到字节数组的自定义类型。一些解释:

首先,我创建了 CustomMaterializedBlobType,Hibernate 使用它来建立字节数组和 Blob 之间的链接,在这里,它的主要作用是提供一个 MutabilityPlan(自定义),它不是真正的数组副本(这是我的问题) :

import org.hibernate.type.AlternativeLobTypes.BlobTypes;
import org.hibernate.type.MaterializedBlobType;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;

public class CustomMaterializedBlobType extends MaterializedBlobType{



/**
 * 
 */
    private static final long serialVersionUID = 1L;

    public CustomMaterializedBlobType() {
        super();
    }

    public CustomMaterializedBlobType(SqlTypeDescriptor sqlTypeDescriptor, BlobTypes<byte[], MaterializedBlobType> blobTypes) {
        super(sqlTypeDescriptor, blobTypes);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected MutabilityPlan<byte[]> getMutabilityPlan() {

        return CustomArrayMutabilityPlan.INSTANCE;
    }
}

现在,MutabilityPlan,除了返回相同的数组而不是创建一个新数组之外什么都不做: import org.hibernate.type.descriptor.java.ArrayMutabilityPlan;

public class CustomArrayMutabilityPlan<T> extends ArrayMutabilityPlan<T>{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public static final CustomArrayMutabilityPlan INSTANCE = new CustomArrayMutabilityPlan();

    @SuppressWarnings({ "unchecked", "SuspiciousSystemArraycopy" })
    public T deepCopyNotNull(T value) {
        if ( ! value.getClass().isArray() ) {
            // ugh!  cannot find a way to properly define the type signature here to
            throw new IllegalArgumentException( "Value was not an array [" + value.getClass().getName() + "]" );
        }

        return value;
    }
}

而且我需要将此自定义类型链接到 Lob,它在我的实体中完成:

@Lob
@Type(type = "CustomMaterializedBlobType")
@Column(name = "FILE_OBJECT")
private byte[] fileObject;

这不是一个很好的解决方案,因为这样,我使我的应用程序依赖于 Hibernate,而不是 JPA(类型注释来自 Hibernate)。如果有人知道我如何在完整的 JPA 中做同样的事情?

于 2013-11-02T16:25:59.210 回答