스프링 부트와 JPA와 함께하는 배치 최적화
JPA의 기본 사항을 정리한다.
스프링부트 + 배치
배치는 DB/네트워크 호출 횟수를 크게 줄여 성능 향상을 할 수 있다.
EX) 개별적인 1000건의 등록 처리는 1000번의 네트워크 호출이 필요하지만, 30개씩 34번의 호출로 처리할 수 있다.
또한 개별적인 배치는 작동이후 즉각적인 Commit이 되어야 유리하다. 장기 실행 트랜잭션을 피하고 장애가 발생한 경우 롤백이 이전 커밋에 영향을 미치지 않는다.
INSERT
설정 고려 Config 정보
spring.jpa.properties.hibernate.jdbc.batch_size = 30
설정 추가한다. (권장 5~30)
한 번에 처리할 batch Size를 설정한다.
spring.datasource.hikari.data-source-properties-reWriteBatchedInserts=true
SQL문이 문자열 버퍼로 재작성 되어 1건의 SQL로 변환된다.
MYSQL
은 그냥 사용하면 된다.POSTGRESQL은 식별자의
@GeneratedValue strategy 속성
에 대해 주의해야 한다.- IDENTITY의 경우 개별 sequence next_val 쿼리를 매 번 발생시키기 때문에 AUTO나 SEQUENCE 메모리 속성을 사용해야 한다.
spring.jpa.properties.hibernate.order_inserts=true
1회의 배치는 1개의 Table만 사용할 수 있다. batch_size의 개수와 상관없이 Author를 적재하고 Book을 적재하면, 2번이 작동되는 개념이다. OneToMany 연관관계를 함께 적재하는 경우 사용하면 한 테이블씩 배치 작업
을 진행한다.
실사용 정보
배치 동시 실행 방법 3가지
엔티티 배치 프로세스 속도가 중요한 경우, 배치처리를 동시에 실행하는 것을 고려할 수 있다.
- Executors
- 포크/조인 프레임워크
- CompletableFuture
UPDATE
설정 고려 Config 정보
spring.jpa.properties.hibernate.jdbc.batch_versioned_date=true
업데이트되어아 햘 엔티티에 @Version 이 지정된 경우 설정. 근데 하이버네이트5부터는 기본적으로 활성화되어있다.
spring.jpa.properties.hibernate.order_updates=true
1:N 관계에서 여러 Table이 사용되는 경우 사용하면 한 테이블에 대한 배치가 끝나고 다른 배치를 실행하여 총 실행 배치를 줄여준다. (배치는 개수와 별개로 1Table에 1개씩 가능하다.)
실 사용 정보
bulk update 방법
//전체 BulkUpdate
@Transactional
@Modifying(flushAutomatically = true, clearAuthomatically = true)
@Query(value = "UPDATE Author a SET a.age = a.age + 1, a.version = a.version")//version을 명시적으로 증가시킨다.
int updateInBulk();
//특정 조건의 Authors만 Update하는 경우
@Transactional
@Modifying(flushAutomatically = true, clearAuthomatically = true)
@Query(value = "UPDATE Author a SET a.age = a.age + 1, a.version = a.version"
+ "WHERE a IN ?1")
int updateInBulk(List<Author> authors);
//실사용 Service
@Transactional
public void updateBulkAuthrosAndBooks(){
authorRepository.updateInBulk();
bookRepository.updateInBulk();
}
//특정 조건 실사용 Service
@Transactional
public void updateAuthorsGtAgeAndBooks(){
List<Author> authors = authorRepository.findGtGivenAge(40);
authorRepository.updateInBulk(authors);
bookRepository.updateInBulk(authors);
}
DELETE
Config
- MYSQL은 다음과 같은 설정이 필요하다.
- jdbc:mysql://localhost:3306/bookstoredb?cachePreStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true
- spring.jpa.properties.hibernates.jdbc.batch_size=30
- spring.jpa.properties.hibernate.jdbc.batch_versioned_date=true
delete는 deleteAllInBatch(), deleteInBatch(Iterable
why? 낙관적 잠금 메커니즘의 이점이 없는 벌크 작업을 트리거 하고 1차캐시가 db와 동기화되지 않는다.
대신 `deleteAll()`, `deleteAll(Iterable<? extends T> entities)` 또는 `delete(T entity)` 를 사용해야 한다.