[JPA]효율적인 데이터 매핑: Native Query에서 JPQL로 전환하기
이번 포스트에서는 Native Query와 JPQL을 사용해 동일한 작업을 수행하는 두 가지 방법을 비교해 보겠습니다.
Aug 21, 2024
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;
}
}

쿼리 조회 결과는
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
엔티티에 매핑해주기 때문에 추가적인 캐스팅이나 필드 설정이 필요 없습니다. 결과적으로 코드가 훨씬 깔끔해지며, 실수를 줄일 수 있습니다.


JPQL을 사용하면 이렇게 간단하게 작업을 수행할 수 있다는 점에서, 보다 효율적인 데이터베이스 접근과 엔티티 매핑을 실현할 수 있습니다.
Share article