조급하면 모래성이 될뿐문제 상황
문제의 원인
데이터가 많아질수록 성능도 저하될 것이다. 1억 개를 저장하려면 1억 번의 select가 나간다.. save 처리방식
해결방법
isNew라는 상태 값을 하나 만들고 default값을 true로 준다. 그러면 처음 객체를 만들 때는 isTrue에 탈것이다. 그다음
첫 번째를 처리할 수 있는 어노테이션이 @PostLoad 두 번째가 @PrePersist이다. 즉, 상태를 false로 변경하는 메서드를 추가한다. 다음으로 isNew의 기준을 변경하기 위해 Persistable 인터페이스를 구현해서, 오버 라이딩해준다. 추가적으로 해당 인터페이스를 구현함으로써 getId함수도 오버 라이딩해주면 된다. 최종 코드는 아래와 같다.
참조
JPA는 보통 데이터를 가져와서 변경하면 변경 감지(dirty checking)를 통해 DB에 업데이트 퀴리를 수행합니다. 이런 업데이트들은 건 별로 JPA를 사용해서도 수 천, 수 만 건의 데이터를 한 번에 업데이트 하는 벌크 업데이트(Bulk Update)쿼리를 사용할 수 있습니다. @Modifying 애너테이션벌크 업데이트를 하기 위해선 나이가 N살 이상인 전체 회원의 나이를 1씩 증가시켜야 한다는 요구사항이 존재한다고 가정하고 이를 구현한 소스 코드 입니다.
이런식으로 전체 업데이트 쿼리를 작성할 수 있습니다. 이 때 @Modifying 애너테이션을 누락시키면 아래와 같은 에러가 발생합니다.
DML operation을 지원하지 않는다는 내용인데요, JPA 기본 동작이
만약
혹시나 위의 두 가지 에러가 발생하더라도 로그에서 친절하게 설명해주기 때문에 간단한 수정을 통해 정상동작 확인 가능합니다. 테스트간단한 테스트 코드를 통해 확인해보겠습니다.
(1) 20살 이상되는 회원은 3명이기 때문에 업데이트 된 row의 수가 3이어야 합니다. 여기서 주의할 점은 DML 쿼리이기 때문에 반드시
여기서도 그렇다면 정상 수행시 로그를 확인해보겠습니다.
먼저 5명의 Member를 insert 한 뒤, update 쿼리는 한 번만 발생한 것을 확인할 수 있습니다. 주의사항벌크 업데이트는 영속성 컨텍스트를 통한 이전 테스트를 간단히 수정해 확인해보겠습니다.
DB에서 다시 조회해 온 하지만 테스트 결과는... 초록불이 보이지 않습니다. 그 이유는 위에서 설명한 바와 같고, 그렇다면 아무리 조심해서 사용한다고해도 언제든지 실수할 가능성이 있으니 이를 미연에 방지하는 것이 더 중요하겠죠?
(1) 영속성 컨텍스트를 관리할 수 있는 EntityManager를 주입받습니다. 이렇게 수정한 뒤 다시 실행하면 성공적인 결과를 확인할 수 있습니다. 하지만 당연히 갓프링께서 더 간단한 방법을 지원해주겠죠? 다시
이렇게 추가해주시면
테스트는 무사히 통과했지만 그렇다면 안전빵으로 무조건 답은 "상황별로 다르다" 입니다. 실무에서는 MyBatis와 JPA를 같이 사용하는 경우도 많고, 벌크 업데이트 후 조회가 필요한 상황이 있을 수도 있습니다만 설계에 따라 벌크 업데이트 로직이 별개로 동작한다면 굳이 옵션을 추가할 필요가 없기 때문입니다. 따라서 상황에 맞게 잘 판단해서 사용하는 것이 실수를 방지하고 메모리를 비웠다가 다시 조회하면서 트랜잭션이 추가로 발생하는 상황 또한 방지해줄 수 있습니다. |