본문 바로가기
java

JPA로 batch insert 하는 방법

by 초특급하품 2020. 2. 20.

여러 entity를 table에 생성을 해야 하는 경우, 하나씩 n번 생성하는 것보다는 bulk로 묶어서 생성하는 편이 여러모로 좋다.

 

JPA의 구현체에 .saveAllIteratable 을 인자로 받는 메소드가 있어서 아주 적은 노력으로 구현했지만, 실제 디버깅 레벨로 쿼리를 출력해보니 하나씩 처리하고 있었다. 인터페이스는 마치 INSERT INTO {TABLE} VALUES ([..., ...]) 꼴의 쿼리로 변환될 것처럼 보였는데, 하나씩 처리하고 있으니 그 원인을 찾아봤다.

 

역시 가장 먼저 이와 관련된 설정 값이 있다.

spring.jpa.properties.hibernate.jdbc.batch_size=20

 

hibernate에게 batch 처리를 가능하도록 그 크기에 대한 설정 값을 0보다 크게 바꿔야 한다. 이렇게 해도 동작은 하지만 여러 entity를 다루는 구간에서는 또 생각처럼 동작하지 않는다. 그 원인은 batch를 관리하는 방법에서 시작된다.

 

하나의 트랜잭션에 영속성을 가지는 여러 개의 타입이 나타날 경우 hibernate는 새로운 batch를 만들어 기록한다. 예를 들어 A 타입을 생성하고, B 타입을 생성한 뒤 다시 A 타입을 생성할 경우에 이 A 타입은 처음 생성한 A 타입과 같음에도 불구하고 다른 batch로 묶인다. 이렇게 되면 나중에 insert 할 때 하나의 쿼리로 묶이지 않는다.

 

이를 해결하기 위해서 서로 다른 batch에 있어도 같은 타입이면 하나의 batch로 실행해주는 옵션을 켠다.

spring.jpa.properties.hibernate.order_inserts=true

 

이렇게 하면 의도한 대로 하나의 쿼리로 bulk insert 되는 entity도 있지만 안 되는 entity도 있다.
바로 아래와 같이 id를 auto increment로 생성하는 녀석들이 bulk insert가 안된다.

@GeneratedValue(strategy = GenerationType.IDENTITY)

 

IDENTITY로 id를 생성한다는 것은 직접 db에 insert를 실행해봐야 알 수 있는 값이다. 이는 hibernate가 영속성을 관리하는 측면에서 보면 그 철학과 어긋난다. 영속성 또는 트랜잭션이 끝나는 시점에 변화가 있는 entity를 db에 반영을 해줘야 하는 입장인데, db에 의존적인 명령이니 앞뒤가 안 맞는 것이다.

 

그래서 이런 이유로 JPA는 IDENTITY에 대해서 batch를 지원하지 않는 방향으로 갔다.

 

'java' 카테고리의 다른 글

Type Erasure와 ParameterizedTypeReference  (0) 2021.01.02
gradle로 spring-boot 프로젝트 설정  (0) 2019.11.19

댓글