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 は、新しい配列を作成する代わりに、同じ配列を返すこと以外には何もしません。

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;

このようにして、アプリケーションをJPAではなくHibernateに依存させたので、これはあまり良い解決策ではありません(型注釈はHibernateから来ています)。完全なJPAで同じことを行う方法を知っている人がいたら?

于 2013-11-02T16:25:59.210 に答える