2013-11-01 2 views
0

Oracle 11g 데이터베이스에 큰 파일을 저장할 때 문제가 발생합니다. Spring과 Hibernate 3.6.9를 JPA 구현으로 사용하고 있습니다.JPA/Hibernate로 LOB 지속하기

지속성은 스프링을 사용하며 다음과 같이 구성되어

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) 
:이 스택 트레이스를 encouter

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

: 나는 계속하고자하는 기업은 다음과 같이 정의 열을 포함

<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> 

나는 많이 봤지만 도움이되는 것은 아무것도 발견하지 못했다. 어떤 사람이 도울 수 있다면 여전히 같은 오류가 발생한다. 다른 Oracle 드라이버를 사용하기 위해 언급 된 링크가 있지만 stacktrace에서 볼 수있는 것처럼이 문제는 최대 절전 모드 코드에 있습니다. 문제는 DB와 관련이 없다고 생각하며 최신 드라이버 ojdbc6을 사용합니다.

+0

JVM에 메모리를 추가하려고 했습니까? 임의로 큰 파일을 메모리에로드 할 수 없으며 항상 작동 할 것으로 기대합니다. JVM에 파일을 저장할 메모리가 충분하지 않으면 OutOfMemoryError가 발생합니다. –

+0

첫 번째 답변에서 해결책을 찾으셨습니까? http://stackoverflow.com/questions/9253323/how-to-persist-large-blobs-100mb-in-oracle-using-hibernate –

+0

@jb Nizet : 현재, 나는 2GB를 할당했다, 충분해야한다, 그렇 겠지? – 893

답변

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 대신 새로 만들 같은 배열 돌아보다 아무 것도하지 않습니다 : 수입 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; 
    } 
} 

그리고 나는 로브이 custimized 유형을 연결해야합니다, 내 법인에서 이루어집니다 :

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

그것은 아주 좋은 해결책이 아니다,이 방법은, 내가 최대 절전 모드의 내 응용 프로그램에 의존했기 때문에 JPA 대신에 (타입 주석은 Hibernate에서 온다.) JPA 전체에서 어떻게 동일한 작업을 수행 할 수 있는지 알고있는 사람이 있습니까?

관련 문제