Web

JPA(Java Persistence API) vs Mapper

kakaroo 2022. 2. 7. 19:24
반응형

article logo

 

웹 어플리케이션에서 관계형 데이터베이스는 빠질수 없는 요소입니다. 객체를 관계형 데이터베이스에서 관리하는 것이 무엇보다 중요합니다. 관계형 데이터베이스가 계속해서 웹 서비스의 중심이 되면서 모든 코드는 SQL 중심이 되어 갑니다.

프로그래밍 언어는 객체지향 패러다임을 지향하는데 반해, 관계형 데이터베이스로 객체지향을 표현할 수가 없었습니다.

서로 지향하는 바가 다른 2개 영역을 중간에 패러다임 일치를 시켜주기 위한 기술이 JPA 입니다.

즉, 개발자는 개발지향적으로 프로그래밍을 하고, JPA가 이를 관계형 데이터베이스에 맞게 SQL을 대신 생성해서 실행합니다. 개발자는 항상 객체지향적으로 코드를 표현할 수 있으니 더 이상 SQL에 종속적인 개발을 하지 않아도 됩니다.

 

앞서 데이터베이스 사용으로 예를 든 MyBatis는 JPA 가 아닙니다. SQL-mapping을 사용하는 영속성(DB 저장) 프레임워크입니다. MyBatis는 개발자가 Native SQL 코드를 작성하고 결과를 객체와 매핑하는것까지 직접 처리해야 합니다.

Table이 변경되고 DTO가 변경될 때마다 mapping에 대한 부분을 재수정해야 하기 때문에 일이 끝나지가 않습니다.

SQL을 작성할 줄 아는 개발자라면 기술적 난이도가 상대적으로 낮기 때문에 쉽게 접할 수 있는 장점이 있지만, 해야 할 일이 많다는 것은 치명적인 약점이 됩니다. 이러한 단점으로 인해 JPA 기술을 많이 사용하는 추세입니다.

 

이에 반해 JPA는 ORM 즉, Object(객체)와 Relational Database(DB)간의 Mapping을 위한 프레임워크입니다. 기술적 난이도가 MyBatis에 비해 상대적으로 높지만, 설정을 통해 대부분의 작업을 손쉽게 자동화 할 수 있습니다.

JPA의 전신은 Hibernate라고 볼 수 있는데 Hibernate 개발자가 interface 형태로 만든 게 JPA 입니다.

JPA의 persistence의 사전적 의미는 지속성 인데, 이는 객체등의 데이터를 저장해서 항상 사용할 수 있게 하는 것을 의미합니다.

 

지금까지 글로만 보면 JPA가 무조건 좋을 것으로 보이는데, 마냥 그렇지만은 않습니다.
간단한 조회 쿼리를 JPA를 이용하면 매우 직관적으로 만들 수 있습니다.

SELECT * FROM notice WHERE id = :id
Optional<Notice> findById(long id);

 

그러나, JPA를 이용해서 복잡한 쿼리를 나타내는 것에는 한계가 있습니다.
그다지 복잡하지 않은 아래의 쿼리를 나타내기 위해 

SELECT * FROM notice
WHERE create_timestamp = :createTimestamp1 AND status = :status1
    OR  create_timestamp >= :createTimestamp2 AND STATUS = :status2

이렇게 긴 메서드를 정의해야하며,

List<Notice> findAllByCreateTimestampAndStatusOrCreateTimestampGreaterThanEqualAndStatus(Timestamp createTimestamp1, String status1, Timestamp createTimestamp2, String status2);

 

CURDATE나 DATE와 같은 SQL 함수를 이용하기 위해서는 @Query를 이용해야 합니다.

SELECT * FROM notice
WHERE create_timestamp = :createTimestamp1 AND status = :status1 AND DATE(open_timestamp) < CURDATE()
    OR create_timestamp >= :createTimestamp2 AND STATUS = :status2 AND
    DATE(open_timestamp) < CURDATE()
@Query("SELECT e FROM #{#entityName} e WHERE e.createTimestamp = :createTimestamp1 AND e.status = :status AND DATE(e.openTimestamp) < CURDATE()"
			+ " OR e.createTimestamp >= :createTimestamp2 AND e.status = :status2 AND DATE(e.openTimestamp) < CURDATE()")
List<Notice> findAllByCreateTimestampAndStatusOrCreateTimestampGreaterThanEqualAndStatus(@Param("createTimestamp1") Timestamp createTimestamp1,
    @Param("status1") String status1, @Param("createTimestamp2") Timestamp createTimestamp2, @Param("status2") String status2);

위의 query 역시 비교적 복잡하지 않은 쿼리라 JPA로 작성이 가능했던 것이며,
통계와 같은 복잡한 쿼리를 작성하려면 SQL 을 직접 작성해야하는 경우가 불가피 할 것입니다.

보통의 경우에는 JPA를 이용하며 복잡한 쿼리를 조회할 때엔 Mapper를 이용하는 것을 권장합니다.

 

Database의 구성과 사용복잡도에 따라 두 방법을 혼용해서 사용도 가능합니다.

 

 

* JPA - https://kakaroo.tistory.com/39?category=1001571 

 

IntelliJ - JPA 활용 (공사중..)

보호되어 있는 글입니다. 내용을 보시려면 비밀번호를 입력하세요.

kakaroo.tistory.com

 

* MyBatis - https://kakaroo.tistory.com/16?category=1001571 

 

Spring Boot - MyBatis

MyBatis는? 쿼리 기반 웹 애플리케이션을 개발할 때 가장 많이 사용되는 SQL 매퍼(Mapper) 프레임워크입니다. 객체 지향 언어인 자바의 관계형 데이터베이스 프로그래밍을 좀 더 쉽게 할 수 있게 도

kakaroo.tistory.com

 

반응형