Framework/Spring (Java)

하이버네이트 배치와 기본키 생성 전략

joyCHAE 2021. 8. 22. 19:50

배치에 관한 공부를 진행하다, 간단한 설정만으로 하이버네이트 배치를 활용해 여러 개의 insert 쿼리를 모아 한 번에 처리할 수 있다는 사실을 알았다. 하이버네이트 배치를 사용하면 여러 개의 쿼리를 한번에 모아서 처리하기 때문에 단건씩 쿼리를 수행할 때에 비해 DB와 통신하는 횟수가 줄어들고, DB에서도 락을 잡는 횟수가 줄어들어 실행속도가 향상된다.

 

설정은 다음과 같다. batch_size에 한꺼번에 insert/update를 실행할 크기만큼 설정하면 된다.

 

applicaiton.yml

spring:
	jpa:
		properties:
			hibernate:
				jdbc:
					batch_size:100

 

 

 

하지만 조금 더 조사해본 결과 크리티컬하게 주의해야 할 점을 발견했다.

 

하지만 조금 더 조사해본 결과 현재 프로젝트 상황에는 하이버네이트 배치를 설정할 수 없음을 알았다.

하이버네이트 문서

 

 

위의 하이버네이트 문서를 살펴보면, 아이디를 Generation.IDENTITY를 사용하는 경우에는 아무리 하이버네이트 설정을 적용해도 insert가 한꺼번에 묶어서 실행되지 않는다는 것을 알 수 있다.

Persistence Context 내부에서 엔티티를 식별할 때는 엔티티 타입과 id값으로 엔티티를 식별하지만, Generation.IDENTITY는 DB에 먼저 insert문을 실행해야만 id 값을 확인 가능하기 때문에 batch insert를 비활성화 한다.

 

 


 

주제가 나온 김에 PK 키생성 전략에 대해서도 소개하겠다.

 

직접 할당: @Id만 사용

자동 생성(@GeneratedValue)

  • IDENTITY : 데이터베이스에 위임(MYSQL)
    • Auto_Increment
  • SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용(ORACLE)
    • @SequenceGenerator 필요
  • TABLE : 키 생성용 테이블 사용, 모든 DB에서 사용
    • @TableGenerator 필요
  • AUTO : 방언에 따라 자동 지정, 기본값

 

 

 

GenerationType에 따라 아이디를 생성방법이 다르다. 그에 따라 필요한 디비 커넥션 갯수가 달라지고 저장을 위한 쿼리 또한 달라진다는 흥미로운 사실!

 

@GeneratedValue(strategy = GenerationType.TABLE)

 

저장 결과

Hibernate: select next_val as id_val from hibernate_sequence for update

Hibernate: update hibernate_sequence set next_val= ? where next_val=?

Hibernate: insert into ex_entity (name, id) values (?, ?)

 

GenerationType.TABLE를 사용할 경우 save() 수행시 insert 쿼리 전에 select, update 쿼리가 사용되는데 이 때 별도의 트랜잭션을 사용하여 추가적인 Connection을 사용하게 된다.

트랜잭션이 끝나기 전까지 Connection이 반납되지 않기 때문에 상황에 따라 DeadLock이 발생할 수도 있다.

참고로 AUTO는 IDENTITY, SEQUENCE, TABLE 중 하나를 자동 선택해주는 친구인데, MySQL 에서는 TABLE을 선택해주는 듯 하다.

 


 

 

@GeneratedeValue(strategy = GenerationType.IDENTITY)

 

저장 결과

Hibernate: insert into ex_entity (name) values (?)

 

기본 키 생성을 데이터베이스에 위임한다. 따라서 PK 값을 DB에 들어가봐야 안다.

하지만 영속 컨텍스트는 PK 값으로 값들을 구분한다.

그래서 보통 커밋 시점에 insert 쿼리가 함께 날아가는 반면, INDENTITY 키생성 전략 하에서는 울며 겨자먹기로 em.persist(member) 시점에 insert 쿼리가 날아가버린다.

 

따라서 모아서 insert 하는 것이 아이덴티티 전략 하에서는 불가능하다!

 

 

 

 

 

 

 


참고 자료: