[JPA]효율적인 데이터 매핑: Native Query에서 JPQL로 전환하기

이번 포스트에서는 Native Query와 JPQL을 사용해 동일한 작업을 수행하는 두 가지 방법을 비교해 보겠습니다.
HootJem's avatar
Aug 21, 2024
[JPA]효율적인 데이터 매핑: Native Query에서 JPQL로 전환하기
Spring Data JPA에서 데이터베이스 쿼리를 실행하고 결과를 매핑하는 방법에는 여러 가지가 있습니다. 이번 포스트에서는 Native Query와 JPQL을 사용해 동일한 작업을 수행하는 두 가지 방법을 비교해 보겠습니다.

1. Native Query

Native Query를 사용하여 직접 SQL 쿼리를 실행하고 결과를 엔티티로 매핑하는 방법을 살펴보겠습니다.
@Repository public class UserRepository { @Autowired private EntityManager em; public User findById() { Query query = em.createNativeQuery("select * from user_tb where id = 1"); Object[] obs = (Object[]) query.getSingleResult(); User user = new User(); user.setId((Integer) obs[0]); user.setCreatedAt((Timestamp) obs[1]); user.setEmail((String) obs[2]); user.setPassword((String) obs[3]); user.setUsername((String) obs[4]); return user; } }
notion image
쿼리 조회 결과는 Object 타입으로 리턴됩니다. obs 에 담기위해 Object[] (오브젝트 배열) 타입으로 다운 캐스팅 해줘야 합니다.
이 데이터를 사용하기 위해 우리는 User 엔티티에 매핑해야 됩니다.
System.out.println(obs[0]); // 1 System.out.println(obs[1]); // 2024-08-21 12:44:09.313894 System.out.println(obs[2]); // ssar@nate.com System.out.println(obs[3]); // 1234 System.out.println(obs[4]); // ssar
매핑하기 위해 obs의 내부를 살펴보면 주석처럼 출력이 됩니다. 배열의 각 인덱스에 컬럼 하나씩 갖고 있는 모습입니다.
User 테이블의 Id 는 Integer 타입, CreatedAt 은 Timestamp 타입입니다. Object 타입이 아니기 때문에 매핑을 하기 위해선 다운 캐스팅을 해야합니다.
user.setId((Integer) obs[0]) Id에 obs[0] 을 Integer 타입으로 다운캐스팅 하여 넣겠다.
 
매핑이 제대로 되었는지 확인하기 위해 테스트 클래스를 생성하겠습니다.
@DataJpaTest // h2, em @Import(UserRepository.class) // br class UserRepositoryTest { @Autowired private UserRepository userRepository; @Test void findById_test() { //given //when User user = userRepository.findById(); //eye System.out.println("test : " + user.getId()); System.out.println("test : " + user.getUsername()); System.out.println("test : " + user.getCreatedAt()); } } /* test : 1 test : ssar test : 2024-08-21 12:44:09.313894 */
테스트 결과를 보면 User 엔티티에 데이터가 잘 매핑된 것을 확인할 수 있습니다. 그러나, 매번 이런 방식으로 데이터를 수동으로 매핑하는 것은 번거롭기때문에 JPQL을 사용하면 더 간단하고 안전하게 작업할 수 있습니다.

2. JPQL

JPQL 쿼리는 엔티티 클래스(User)를 직접 참조하며, 쿼리 결과를 자동으로 엔티티로 매핑해줍니다. 이를 통해 코드가 훨씬 간결해지고 유지보수가 쉬워집니다.
public User findById1() { Query query = em.createQuery("select u from User u where u.id = 1", User.class); User user = (User) query.getSingleResult(); return user; }
@Test void findById1_test() { User user = userRepository.findById1(); System.out.println("test1 : " + user.getId()); System.out.println("test1 : " + user.getUsername()); System.out.println("test1 : " + user.getCreatedAt()); }
select u from User u where u.id = 1
쿼리문에 사용된 User은 엔티티 클래스 이고 마지막에 붙인 User.class 가 자동으로 엔티티와 매핑되도록 해줍니다.
이처럼 JPQL을 사용하면, Hibernate가 결과를 자동으로 User 엔티티에 매핑해주기 때문에 추가적인 캐스팅이나 필드 설정이 필요 없습니다. 결과적으로 코드가 훨씬 깔끔해지며, 실수를 줄일 수 있습니다.
notion image
notion image
JPQL을 사용하면 이렇게 간단하게 작업을 수행할 수 있다는 점에서, 보다 효율적인 데이터베이스 접근과 엔티티 매핑을 실현할 수 있습니다.
 
 
Share article

[HootJem] 개발 기록 블로그