한번에 대량의 데이터를 저장해야 하는 경우가 있을 것이다.
예를 들어 엑셀 업로드 하면 해당 데이터들을 DB에 저장해야 한다.
데이터가 3만 건 존재한다고 했을 때 어떻게 처리 해야 할 것인가?
먼저 주의점에 대해서 나열해보자.
- 3만 건의 데이터를 영속화 한 뒤 flush 하는 방법은 과연 괜찮을까? 메모리가 충분하다면 3만 건 데이터는 문제 없이 처리될 것이다. 다만, 그 이상의 데이터를 영속화 하게 된다면 out of memory 예외를 만나게 된다.
- 많은 데이터를 영속화해서 flush 하면 메모리 오류가 나니~ 건건이 영속화하고 flush 하면 되겠네? 라고 생각하면 이 또한 큰 오산이다. 처리 속도도 오래 걸릴 뿐더러 데이터 양만큼의 통신이 발생하기 때문에 비효율적이다.
그럼 방법이 뭔데?
의외로 해답은 단순하다.
200개씩 데이터를 영속화하고 flush 를 반복해 주면 된다.
이와같은 방법은 처리 속도, 통신 비용 감소, 메모리 오류 방지를 할 수 있다.
테스트 해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | @Slf4j @RunWith(SpringRunner.class) @SpringBootTest public class BulkTest { @PersistenceContext private EntityManager em; @Value("${spring.jpa.properties.hibernate.jdbc.batch_size}") private int batchSize; @Test public void batch사이즈() { assertThat(20, is(batchSize)); } @Test @Transactional public void bulkInsert() { for (int i = 0; i < 10000; i++) { BulkMember member = new BulkMember(); member.setId(i); member.setName("nklee"); em.persist(member); if (i % batchSize == 0) { // Flush a batch of inserts and release memory. em.flush(); em.clear(); } } em.flush(); em.clear(); } } @Data @Entity @Table(name = "BULK_MEMBER") class BulkMember { @Id private int id; @Lob private String name; } | cs |
한 가지 주의해야 할 점이 있다.
엔티티 기본키 생성 전략을 @GeneratedValue(strategy = GenerationType.IDENTITY) 로 사용하면 의도한 대로 bulk insert 처리가 되지 않는다.
1 2 3 | @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; | cs |
왜냐하면 IDENTITY 전략은 DB의 auto_increment 를 사용하기 때문이다.
무슨 말이냐하면 엔티티 @Id 에 값이 채워지기 위해서는 DB에 insert를 해야지만 그 값을 알 수 있다는 것이다.
즉, 다음과 같이 동작하기 때문에 bulk insert 처리가 의미 없어지게 된다.
DB에 일단 저장 -> auto_increment로 생성된 값을 가져온 후 -> 엔티티를 영속화
'프로그래밍' 카테고리의 다른 글
SCP command 프로그램 (0) | 2018.05.17 |
---|---|
3. Spring Cloud를 이용한 MSA 구축하기 - config client (0) | 2018.05.15 |
linux 장비 원격 실행 프로그램 (0) | 2018.05.08 |
spring boot swagger2 사용하기 (0) | 2018.02.01 |
15. [JPA] Spring Data JPA (0) | 2017.12.14 |
20. [JPA] lombok 사용 시 주의사항 (0) | 2017.11.28 |
19. [JPA] 트랜잭션 테스트 (0) | 2017.11.27 |
18. [JPA] N+1 문제 (fetch 조인 해결 방안) (0) | 2017.11.24 |