[SPRING] 스프링 데이터와 하이버 네이트를 사용할 때 어떻게 백그라운드 스레드를 올바르게 수행 할 수 있습니까?
SPRING스프링 데이터와 하이버 네이트를 사용할 때 어떻게 백그라운드 스레드를 올바르게 수행 할 수 있습니까?
Spring Data와 Hibernate를 사용하는 간단한 Tomcat webapp을 만들고 있습니다. 많은 작업을 수행하는 하나의 엔드 포인트가 있으므로 작업이 완료되는 동안 웹 요청이 10 분 이상 멈추지 않도록 작업을 백그라운드 스레드로 오프로드하려고합니다. 그래서 나는 component-scan 패키지에 새로운 Service를 작성했다 :
@Service
public class BackgroundJobService {
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
public void startJob(Runnable runnable) {
threadPoolTaskExecutor.execute(runnable);
}
}
그런 다음 Spring에서 ThreadPoolTaskExecutor를 구성하십시오.
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
</bean>
이것은 모두 잘 작동합니다. 그러나이 문제는 Hibernate에서 발생한다. 내 runnable 내부 쿼리 절반 밖에 작동하지 않습니다. 내가 할 수있는:
MyObject myObject = myObjectRepository.findOne()
myObject.setSomething("something");
myObjectRepository.save(myObject);
그러나 게으른로드 된 필드가 있으면 실패합니다.
MyObject myObject = myObjectRepository.findOne()
List<Lazy> lazies = myObject.getLazies();
for(Lazy lazy : lazies) { // Exception
...
}
다음과 같은 오류가 발생합니다.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.stackoverflow.MyObject.lazies, could not initialize proxy - no Session
그래서 나 (Hibernate newbie)는 새로운 쓰레드가 이들 집에서 만든 쓰레드에 대한 세션을 가지고 있지 않지만 Spring Data는 자동으로 HTTP 요청 쓰레드를위한 새로운 세션을 생성하고 있다고 생각한다.
@Transactional 메소드 내부에서부터 모든 것을함으로써 약간의 문제를 해결할 수 있었지만, 웹 요청에 대해서는 정상적으로 작동하는 메소드를 사용할 수 없기 때문에 매우 좋은 해결책은 아닙니다. .
감사.
해결법
-
==============================
1.Spring에서는 자신 만의 집행자가 필요 없습니다. 간단한 주석 @Async가 작업을 수행합니다. 그걸로 서비스에 heavyMethod에 주석을 달고 void 나 Future 객체를 반환하면 배경 스레드가 생깁니다. 컨트롤러 수준에서 비동기 주석을 사용하지 마십시오. 요청 풀이 요청자 풀에서 비동기 스레드를 생성하고 '요청 수락 자'가 부족할 수 있습니다.
Spring에서는 자신 만의 집행자가 필요 없습니다. 간단한 주석 @Async가 작업을 수행합니다. 그걸로 서비스에 heavyMethod에 주석을 달고 void 나 Future 객체를 반환하면 배경 스레드가 생깁니다. 컨트롤러 수준에서 비동기 주석을 사용하지 마십시오. 요청 풀이 요청자 풀에서 비동기 스레드를 생성하고 '요청 수락 자'가 부족할 수 있습니다.
게으른 예외 문제는 세션이없는 새 스레드로 의심되는 경우에 발생합니다. 이 문제를 피하려면 비동기 메서드가 전체 작업을 처리해야합니다. 이전에로드 된 엔티티를 매개 변수로 제공하지 마십시오. 이 서비스는 EntityManager를 사용할 수 있으며 트랜잭션이 될 수도 있습니다.
나 자신을 위해 @Async와 @Transactional을 병합하지 않기 때문에 어느 쪽의 방법 으로든 서비스를 실행할 수있다. 방금 서비스 주위에 비동기 래퍼를 만들고 대신 필요할 경우이 패키지를 사용합니다. (이는 예를 들어 테스트를 간소화합니다)
@Service public class AsyncService { @Autowired private Service service; @Async public void doAsync(int entityId) { service.doHeavy(entityId); } } @Service public class Service { @PersistenceContext private EntityManager em; @Transactional public void doHeavy(int entityId) { // some long running work } }
-
==============================
2.아마도 DAO 코드에서 트랜잭션을 처리하고 Spring은 트랜잭션을 닫을 때 세션을 닫습니다.
아마도 DAO 코드에서 트랜잭션을 처리하고 Spring은 트랜잭션을 닫을 때 세션을 닫습니다.
모든 비즈니스 로직을 단일 트랜잭션으로 집어 넣어야합니다.
SessionFactory를 코드에 삽입하고 SessionFactory.openSession () 메소드를 사용할 수 있습니다. 문제는 거래를 관리해야한다는 것입니다.
-
==============================
3.방법 # 1 : JPA Entity Manager
방법 # 1 : JPA Entity Manager
백그라운드 스레드에서 : 엔티티 관리자를 삽입하거나 스프링 컨텍스트에서 가져 오거나 참조로 전달하십시오.
@PersistenceContext private EntityManager entityManager;
그런 다음 공유 엔티티를 사용하지 않으려면 새 엔티티 관리자를 만듭니다.
EntityManager em = entityManager.getEntityManagerFactory().createEntityManager();
이제 트랜잭션을 시작하고 Spring DAO, 저장소, JPA 등을 사용할 수 있습니다.
private void save(EntityManager em) { try { em.getTransaction().begin(); <your database changes> em.getTransaction().commit(); } catch(Throwable th) { em.getTransaction().rollback(); throw th; } }
방법 # 2 : JdbcTemplate
낮은 수준의 변경이 필요하거나 작업이 간단하면 JDBC 및 쿼리를 사용하여 수동으로 수행 할 수 있습니다.
@Autowired private JdbcTemplate jdbcTemplate;
그리고 어딘가에 당신의 방법 :
jdbcTemplate.update("update task set `status`=? where id = ?", task.getStatus(), task.getId());
참고 : JTA를 사용하거나 JpaTransactionManager에 의존하지 않는 한 @Transactional에서 멀리 떨어져있는 것이 좋습니다.
from https://stackoverflow.com/questions/24916104/how-do-i-properly-do-a-background-thread-when-using-spring-data-and-hibernate by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 스프링 부트로 Maven 리소스 필터링 : 자리 표시자를 해결할 수 없습니다. (0) | 2018.12.15 |
---|---|
[SPRING] spring-data-mongodb 멀티 테넌트 만들기 (0) | 2018.12.15 |
[SPRING] 내 웹 앱의 봄부터 '스레드 바운드 요청 없음'오류 발생 (0) | 2018.12.15 |
[SPRING] Spring Boot 2.0 마이그레이션 후 : driverClassName에 jdbcUrl이 필요합니다. (0) | 2018.12.15 |
[SPRING] Spring 컨트롤러로 에러 404를 처리한다. (0) | 2018.12.15 |