본문 바로가기

Spring&IntelliJ

JPA DB에서 데이터 가져오기

출처: https://www.youtube.com/watch?v=4S9Td7L6_2o&list=PLOSNUO27qFbvzGd3yWbHISxHctPRKkctO&index=5

요약: 

1. 어떠한 라이브러리에 있는 메서드가 반환하는 것이 객체이고 그것을 받아 사용하기 위해서는 내 측에서는 반드시 그 클래스에 대한 default생성자가 기본적으로 존재해야 한다는 것이다.

2. JPA의 EntityManager가 관리하는 영속객체라면 수정을 했을시 따로 EntityManager에게 update요청을 하지 않더라도 commit()된다면 DB로의 수정 쿼리가 날아가고 DB에 수정내역이 반영된다.

이전시간까지 jpa를 이용하여 db에 데이터를 저장하는 연습을 하고 이번 시간에는 db에 저장되어 있던 데이터를 가지고와서 다루는 연습을 한다.

우선 기본적인 세팅으로는 DB안에 어떠한 데이터가 있는 상황을 전재로 하고 들어간다.

연습을 위해 아래와 같은 코드를 작성했을때 다음과 같은 오류를 볼수 있다. 물론 어떠한 오류가 메인 오류인지 혼자서는 파악할 수 없고 강사가 지목한 것이 No default constructor for Entity 라는 오류이니 그 오류에 집중하는 것이다. 그리고 그것이 이번 강의에서 강사가 알려주고자 하는 것이다.

왜 No default constructor for Entity라는 오류가 발생할까? 이유는 다음과 같고 그 이유에 대해 한번쯤 생각해 보는 것이 좋다는 것이 강사의 의견. 근데 매우 쉽다.

EntityManager가 가지고 있는 find메서드의 반환형은 Customer객체이다. 이전에 배웠듯이 EntityManager는 jpa에 속하고 jpa는 jdbc를 기반으로 한다. jdbc가 db로 부터 가져온 ResultSet의 데이터를 이용하여 결과적으로 EntityManager의 find함수는 Customer객체를 생성해 내야 한다. 많은 생성자가 있을수 있지만 find메서드가 가장 먼저 찾는 생성자는 (find메서드 뿐만 아니라 다른 어떠한 메서드도 마찬가지일 것이다)Default 생성자이다. 하지만 나는 따로 default생성자를 만들어주지 않았으므로 오류가 나는 것이다. 즉 여기서 알아두어야 할 것은 어떠한 라이브러리에 있는 메서드가 반환하는 것이 객체이고 그것을 받아 사용하기 위해서는 내 측에서는 반드시 그 클래스에 대한 default생성자가 기본적으로 존재해야 한다는 것이다.

위 오류에 대한 해결책은 간단함. 나는 lombok라이브러리를 사용하고 있으니 Customer클래스에 @NoArgsConstructor 어노테이션만 붙여주면 되는 것임.

실습 과정에서 흥미로운 점 찾아냄. 
commit()메서드를 주석처리하고 위와 같이 find하고 setName으로 수정시켜 주면 find에 해당하는 select쿼리만 hibernate가 sql쿼리로 날리고 setName에 해당하는 update쿼리는 hibernate가 sql쿼리로 날리지 않음. 왜 그런가? 결국은 모든 트랜잭션안의 모든 명령은 commit()메서드가 호출되는 시점에 SQL문으로 바뀌어 DB에 날려지게 되는 것임. 그런데 commit메서드가 주석처리되어있으니 그렇지 못한것. 다만 조회에 해당하는 find메서드의 select쿼리는 단순조회이므로 commit이전에도 DB로 sql쿼리를 날려주는 것같음.

또한 DB에 update를 해달라는 요청을 EntityManager에게 하지 않았음에도 update가 이루어졌다는 것도 주목해야함. 어떻게 이것이 가능함? 위에서 조회된 Customer객체(find메서드가 반환하는 객체)는 이미 JPA의 EntityManager가 관리하는 영속객체임. 따라서 이 객체를 수정하고 commit해주면 따로 EntityManager에게 update요청을 하지 않더라도 DB의 원본데이터를 수정하는 update SQL쿼리가 날라가게 되는 것입니다.