복붙노트

[SPRING] Spring @Async : LAZY 콜렉션의 null 동면 세션

SPRING

Spring @Async : LAZY 콜렉션의 null 동면 세션

나는 서비스 계층 메소드에서 @Async 어노테이션을 사용하고있다.

@OneToMany 컬렉션 필드를로드 할 때 모든 것이 잘 작동하지만, LAZY로드 된 요소에 액세스하려고하면 Hibernate SessionImplementor 객체 세션이 null이라는 것을 알았습니다. 분명히 저에게는 예외가 있습니다.

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
....    

여기 내 컬렉션 필드가 있습니다 :

@OneToMany(mappedBy="abc", fetch=FetchType.LAZY, cascade=CascadeType.REMOVE)
@OrderBy(value="xsd asc")
@JsonIgnore
private Set<Item> items = new HashSet<Item>();

어떻게하면 @Async 컨텍스트 내에서 객체를로드하기 위해 최대 절전 세션을 바인딩 할 수 있습니까?

편집하다

내 trancactionManager / entityManager 구성은 다음과 같습니다.

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emf"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter">

    </property>
    <property name="packagesToScan" value="it.domain"/>

    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
            <!--${hibernate.format_sql} -->
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
            <!-- ${hibernate.show_sql} -->
            <prop key="hibernate.show_sql">false</prop> 

            <prop key="hibernate.connection.charSet">UTF-8</prop>

            <prop key="hibernate.max_fetch_depth">3</prop>
            <prop key="hibernate.jdbc.fetch_size">50</prop>
            <prop key="hibernate.jdbc.batch_size">20</prop>

            <prop key="org.hibernate.envers.audit_table_suffix">_H</prop>
            <prop key="org.hibernate.envers.revision_field_name">AUDIT_REVISION</prop>
            <prop key="org.hibernate.envers.revision_type_field_name">ACTION_TYPE</prop>
            <prop key="org.hibernate.envers.audit_strategy">org.hibernate.envers.strategy.ValidityAuditStrategy</prop>
            <prop key="org.hibernate.envers.audit_strategy_validity_end_rev_field_name">AUDIT_REVISION_END</prop>
            <prop key="org.hibernate.envers.audit_strategy_validity_store_revend_timestamp">True</prop>
            <prop key="org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name">AUDIT_REVISION_END_TS</prop>               
        </props>
    </property>
</bean>

<jpa:repositories base-package="it.repository"
                  entity-manager-factory-ref="emf"
                  transaction-manager-ref="transactionManager"/>

<jpa:auditing auditor-aware-ref="auditorAwareBean" />
<bean id="auditorAwareBean" class="it.auditor.AuditorAwareBean"/>

해결법

  1. ==============================

    1.Spring의 트랜잭션 컨텍스트는 ThreadLocals를 사용하여 보존됩니다. 즉, SessionFactory는 요청을 처리하는 스레드에서만 사용할 수 있으므로 새 스레드를 만들면 null과 해당 예외가 발생합니다.

    Spring의 트랜잭션 컨텍스트는 ThreadLocals를 사용하여 보존됩니다. 즉, SessionFactory는 요청을 처리하는 스레드에서만 사용할 수 있으므로 새 스레드를 만들면 null과 해당 예외가 발생합니다.

    @Async 메서드가하는 일은 TaskExecutor를 사용하여 다른 스레드에서 메서드를 실행하는 것입니다. 위에서 설명한 문제가 서비스에서 발생하고 있습니다.

    나는 Spring의 JpaTransactionManager 문서에서 인용한다.

    어노테이션을 보존하려면 Hibernate CurrentSessionContext를 살펴보고 어떻게 든 세션을 직접 관리해야합니다.

    자세한 내용은이 질문을 참조하십시오.

  2. ==============================

    2.나는 해결책을 찾기 위해 노력하면서 며칠을 보내고 같은 문제를 안고 마침내 해결책을 얻었다. 같은 문제가있는 사람들을 위해 찾은 세부 정보를 공유하고 싶습니다.

    나는 해결책을 찾기 위해 노력하면서 며칠을 보내고 같은 문제를 안고 마침내 해결책을 얻었다. 같은 문제가있는 사람들을 위해 찾은 세부 정보를 공유하고 싶습니다.

    1st - @ Async-annotated 메소드는 @ Controller- 또는 @ RestController-annotated 빈이 아닌 별도의 빈에 선언되어야합니다.

    둘째 - 선언 된 @Async 메서드 내에서 호출되는 @Transactional 메서드를 선언해야합니다. 그러나 @Async 메서드에서 호출 된 첫 번째 메서드는 @Transactional로 정의해야합니다. 메서드 실행 스택에서 두 번째 또는 세 번째 수준의 @Transactional 메서드를 사용 했으므로 문제가 해결되지 않았고 이틀 동안 무슨 일이 일어나고 있는지 파악하려고했습니다.

    그래서 할 수있는 가장 좋은 방법은

    @Controller
    ControllerBean {
    
        @Autowired
        AsyncService asyncService;
    
        public controllerMethod() {
            asyncService.asyncMethod();
        }
    }
    
    @Service
    AsyncService {
        @Autowired
        TransactionalService transactionalService;
    
        @Async
        public asyncMethod() {
            transactionalService.transactionalMethod();
        }
    }
    
    @Service
    TransactionalService {
        @Autowired
        SomeOtherService someOtherService;
    
        @Autowired
        EntityRepository entityRepository;
    
        @Transactional
        public transactionalMethod() {
            Entity entity = entityRepository.findOne(12345);
    
            someOtherService.doWork(entity);
        }
    }
    
    @Service
    SomeOtherService {
    
        @Autowired
        EntityRepository entityRepository;
    
        @Transactional
        public doWork(Entity entity) {
            // fetch lazy properties, save, etc. without any session problems...
            entity.getLazyProperties(); 
    
            entityRepository.save(entity);
        }
    }
    
  3. ==============================

    3.정상적인 환경 (@Async없이)에서는 트랜잭션이 호출 계층 구조를 통해 하나의 Spring 구성 요소에서 다른 구성 요소로 전파됩니다.

    정상적인 환경 (@Async없이)에서는 트랜잭션이 호출 계층 구조를 통해 하나의 Spring 구성 요소에서 다른 구성 요소로 전파됩니다.

    @Transactional Spring @Component가 @Async로 주석 된 메소드를 호출 할 때 이것은 발생하지 않습니다. 비동기 메소드에 대한 호출은 태스크 실행기에 의해 나중에 스케줄되고 실행되므로 '트랜잭션'컨텍스트없이 '새로운'호출로 처리됩니다. @Async 메소드 (또는 선언 된 컴포넌트)가 @Transactional이 아닌 경우 Spring은 필요한 트랜잭션을 관리하지 않습니다.

    @Async 메서드를 호출하는 메서드에 주석을 추가하고 작업 한 경우 알려주십시오.

  4. from https://stackoverflow.com/questions/25083295/spring-async-null-hibernate-session-on-lazy-collection by cc-by-sa and MIT license