본문 바로가기
Spring/Spring Data JPA

JPA Hibernate Bulk Save , Multi save

by 아이티.파머 2019. 1. 3.
반응형

 

Hibernate 특징

Hibernate는 새로이 삽입 된 모든 Customer인스턴스를 세션 레벨1 cache에 캐시 하므로 트랜잭션이 끝나면 100000 개의 엔티티가 영속 컨텍스트에 의해 관리됩니다. JVM에 할당 된 최대 메모리가 다소 적 으면이 예제는에서 실패 할 수 OutOfMemoryException있습니다. Java 1.8 JVM은 사용 가능한 RAM의 1/4 또는 1Gb를 할당하여 힙에 100,000 개의 객체를 쉽게 수용 할 수 있습니다.

 

장기 실행 트랜잭션은 연결 풀을 고갈시켜 다른 트랜잭션이 처리 할 기회를 얻을 수 없습니다.

 

JDBC 일괄 처리는 기본적으로 활성화되어 있지 않으므로 모든 삽입 문에는 데이터베이스 왕복이 필요합니다. JDBC 배치를 사용하려면 hibernate.jdbc.batch_size속성을 10에서 50 사이의 정수로 설정하십시오 .

 

 

 

일괄 처리 속성 (Hibernate. properties)

 

JDBC 일괄 처리

JDBC는 단일 PreparedStatement로 표현할 수있는 SQL 문을 함께 일괄 처리 할 수 ​​있도록 지원합니다. 구현 방식은 일반적으로 드라이버가 데이터베이스에 대한 네트워크 호출을 절약 할 수있는 한 번의 호출로 서버에 일괄 작업을 보냅니다. Hibernate는 JDBC 배치를 활용할 수 있습니다. 다음 설정은이 동작을 제어합니다.

 

hibernate.jdbc.batch_size

드라이버에게 배치를 실행하기 전에 Hibernate가 함께 배치 할 문장의 최대 수를 제어한다. 0 또는 음수는이 기능을 비활성화합니다.

 

hibernate.jdbc.batch_versioned_data

일부 JDBC 드라이버는 일괄 처리가 실행될 때 잘못된 행 수를 반환합니다. JDBC 드라이버가이 범주에 속하면이 설정을로 설정해야합니다 false. 그렇지 않으면 Hibernate가 여전히 버전 화 된 엔티티에 대해 DML을 배치하고 여전히 낙관적 인 잠금 검사에 반환 된 행 수를 사용하도록 허용하는 이것을 사용하는 것이 안전합니다. 5.0부터 기본값은 true입니다. 이전 버전 (3.x 및 4.x)은 이전에는 false였습니다.

 

hibernate.jdbc.batch.builder

일괄 처리 기능을 관리하는 데 사용되는 구현 클래스의 이름입니다. Hibernate의 기본 구현에서 전환하는 것은 거의 좋은 생각이 아니다. 그러나 원하는 경우이 설정은 org.hibernate.engine.jdbc.batch.spi.BatchBuilder사용할 구현을 명명합니다 .

 

hibernate.order_updates

Hibernate로 하여금 엔티티 타입과 업데이트되는 아이템의 프라이 머리 키 값에 의해 SQL 업데이트를 정렬하도록한다. 이렇게하면 더 많은 일괄 처리를 사용할 수 있습니다. 동시성이 높은 시스템에서는 트랜잭션 교착 상태가 줄어 듭니다. 성능에 영향을 미치기 때문에 이전과 후에 벤치마킹을 통해 응용 프로그램이 실제로 도움이되는지 아픈지 확인하십시오.

 

hibernate.order_inserts

Hibernate가 더 많은 일괄 처리가 사용될 수 있도록 삽입을 정렬하도록한다. 성능에 영향을 미치기 때문에 이전과 후에 벤치마킹을 통해 응용 프로그램이 실제로 도움이되는지 아픈지 확인하십시오.

 

버전 5.2부터, Hibernate는 주어진 JDBC hibernate.jdbc.batch_size설정 값에 의해 주어진 전역 JDBC 배치 크기를 오버라이드 (override) 할 수있다 Session.

 

 

예제 

일괄 처리 방식으로 Hibernate / JPA 두가지 방식을 소개 한다.

 

1. Hibernate 방식 - EntityManager  

public abstract class AbstractBulkRepository {

  @Value("${spring.jpa.properties.hibernate.jdbc.batch_size:500}")
  private int batchSize;

  @Autowired
  AdGroupJpaRepository adGroupJpaRepository;

  @PersistenceContext
  EntityManager entityManager;


  public <T> int bulkDataSave(List<T> entities) throws DataAccessException {

    AtomicInteger adGroupInsightIndex = new AtomicInteger(1);

    entities.forEach(entity -> {

      entity = entityManager.merge(entity);

      //entityManager.setFlushMode(FlushModeType.COMMIT)
      //entityManager.persist(entity);
      if (adGroupInsightIndex.get() > 0 && adGroupInsightIndex.get() % batchSize == 0) {
        entityManager.flush();
        entityManager.clear();
      }
      adGroupInsightIndex.getAndIncrement();

    });

    entityManager.flush();
    entityManager.clear();
    //entityManager.close();

    // 로그 용도
    //entitys.get(0).getClass().getName()

    return adGroupInsightIndex.get();

  }

 

 

2. 일반 JPARepository

일반 JPA Repository로 일괄 업데이트 저장을 하기 위해서는 하이버 네이트 설정을 추가해 주어야 한다.

application.ymlhibernate property 에 몇가 지 속성을 추가한다.   (위에 일괄처리 속성 참고)

 

hibernate.jdbc.batch_size: 200                  # 배치사이즈 설정 
hibernate.jdbc.batch_versioned_data: true   # 에러가 났을때 잘못된 행수 반환 여부 
hibernate.order_inserts: true                    # insert 구문을 묶어서 일괄처리 함
hibernate.order_updates: true                  # update 구문을 묶어서 일괄처리함

 

2.1 bulkClass 예제 

public class bulkClass {
  @Autowired
  AdGroupJpaRepository adGroupJpaRepository;

  @Transactional(transactionManager = "transactionManager", propagation = Propagation.REQUIRED)
  public boolean dataSave(List<AdGroupMeta> adSetOriginalMetaData) {

  
  List<AdGroupEntity> adGroupEntityList = new ArrayList<>();
  AtomicInteger adGroupInsightIndex = new AtomicInteger(1);

  adSetOriginalMetaData.forEach(adSetMetaData -> {
  try {

    if (adGroupInsightIndex.get() > 0 && adGroupInsightIndex.get() % batchSize == 0) {

	  ...

    // AdGroup 데이터 저장
    this.adGroupJpaRepository.saveAll(adGroupEntityList);
    this.adGroupJpaRepository.flush();
    adGroupEntityList.clear();

    }
    adGroupInsightIndex.getAndIncrement();

    } catch (Exception e) {
       e.printStackTrace();
    }
  });

  this.adGroupJpaRepository.saveAll(adGroupEntityList);
  this.adGroupJpaRepository.flush();


  return true;
  }
}

 

 

2.2 allpication.yml 설정

Properties

spring:
	devtools:
		restart:
			enabled: false
	datasource:
		driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://IP:3306/DB_NAME?useUnicode=true&characterEncoding=utf8
        username: id
        password: password!@#
	jpa:
      generate-ddl: true
      open-in-view: true
      show-sql: true
    hibernate:
      ddl-auto: validate
      database: mysql
      database-platform: org.hibernate.dialect.MySQL5Dialect
      properties:
        hibernate.jdbc.batch_size: 200
        hibernate.jdbc.batch_versioned_data: true
        hibernate.order_inserts: true
        hibernate.order_updates: true
        hibernate.enable_lazy_load_no_trans: true
    data:
	    jpa:
    		repositories:
    			enabled: true

 

 

 

 

 

 

 

---------------------------------------------------------------------------------

일괄 처리 공통 처리 부분 좋은 예제 

 

https://memorynotfound.com/hibernate-jpa-batch-insert-batch-update-example/

https://frightanic.com/software-development/jpa-batch-inserts/

 

하이버 네이트 배치 처리 설명 

http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#batch

 

---------------------------------------------------------------------------------

영속성 관리 참고 

http://cocomo.tistory.com/334

https://wckhg89.github.io/archivers/JPA

http://victorydntmd.tistory.com/207

https://www.slideshare.net/ssusere4d67c/jpa-53004111

 

---------------------------------------------------------------------------------

참고 https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/chapters/batch/Batching.html

반응형