성능 최적화(배치 처리)

Mina Park·2022년 12월 3일
0
post-thumbnail
  • 많은 데이터의 배치처리가 필요한 상황인 경우, 일반적인 방식으로 엔티티를 계속 조회하면 영속성 컨텍스트에 많은 엔티티가 쌓이면서 메모리 부족 오류가 발생
  • 따라서 이런 배치 처리는 적절한 단위로 영속성 컨텍스트 초기화가 필요

1) JPA 등록 배치

  • (1-1) 데이터 등록
    • Ex) 100개의 데이터 등록, 10개마다 영속성 컨텍스트 초기화
	public void insertBoardBatch() {

		EntityManager em = emf.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();

		for (int i = 0; i < 100; i++) {
			Board board = Board.builder().title("board" + i).build();
			em.persist(board);

			if(i%10 == 0) {
				em.flush();
				em.clear();
			}
		}

		tx.commit();
		em.close();
	}

  • (1-2) 데이터 수정
    • 페이징 처리
    • 커서 기능 사용

2) JPA 페이징 배치 처리

  • 페이징 쿼리로 조회하면서 데이터 변경
  • 페이지 단위마다 영속성 컨텍스트 플러시, 초기화

3) 하이버네이트 scroll 사용

  • JDBC 커서를 지원하는 하이버네이트의 전용 기능(JPA는 JDBC 커서 지원 x)
    • Ex) 124개의 데이터 수정, 10개마다 영속성 컨텍스트 초기화
	public void updateBoardBatch() {
		EntityManager em = emf.createEntityManager();
		EntityTransaction tx = em.getTransaction();
		Session session = em.unwrap(Session.class); //하이버네이트 세션 구현

		tx.begin();

		ScrollableResults scroll = session.createQuery("select b from Board b")
						.setCacheMode(CacheMode.IGNORE) //2차캐시 기능 off
						.scroll(ScrollMode.FORWARD_ONLY);

		int cnt = 0;

		while(scroll.next()) { //반환받은 ScrollableResults 객체를 하나씩 조회
			Board board = (Board) scroll.get(0);
			String newTitle = "batch update" + cnt;
			board.changeTitle(newTitle);

			cnt ++;
			if(cnt % 10 == 0) {
				session.flush();
				session.clear(); //영속성 컨텍스트 초기화
			}
		}

		tx.commit();
		em.close();
	}
	public Board changeTitle(String newTitle) {
		this.title = newTitle;
		return this;
	}


4) 하이버네이트 무상태 세션 사용

  • 영속성 컨텍스트를 만들지 않고 2차 캐시도 사용하지 않음
  • 영속성 컨텍스트가 없으므로 플러시, 초기화할 필요 X
  • 대신 엔티티 수정시 무상태 세션이 제공하는 update() 메소드를 직접 호출해야 함
public void updateBoardStateless() {
		SessionFactory sessionFactory = emf.unwrap(SessionFactory.class); //하이버네이트 세션팩토리 구현
		StatelessSession session = sessionFactory.openStatelessSession();
		Transaction tx = session.beginTransaction();

		ScrollableResults scroll = session.createQuery("select b from Board b").scroll();

		while(scroll.next()) { //반환받은 ScrollableResults 객체를 하나씩 조회
			Board board = (Board) scroll.get(0);
			String newTitle = "stateless update";
			board.changeTitle(newTitle);
			session.update(board); //직접 호출
		}

		tx.commit();
		session.close();
	}

0개의 댓글