JPA vs MyBatis vs JDBC vs QueryDSL vs JPQL 비교 및 분석
Spring 환경에서 데이터베이스를 다룰 때 사용되는 대표적인 기술로 JPA, MyBatis, JDBC, QueryDSL, JPQL 등이 있다.
각 기술은 특징, 장점, 단점, 사용 방식이 다르며 프로젝트 요구 사항에 따라 적절한 기술을 선택해야 한다.
1. JDBC (Java Database Connectivity)
특징
• Java의 표준 데이터베이스 API.
• SQL을 직접 작성하여 데이터베이스와 통신.
• Connection, Statement, ResultSet 등을 사용하여 데이터 처리.
장점
- 직접적인 SQL 사용 → 데이터베이스의 모든 기능 활용 가능.
- 가장 빠른 성능 → 별도의 프레임워크 없이 최소한의 오버헤드로 실행.
- 단순한 프로젝트에서 유용 → JPA, MyBatis보다 가볍고 간단한 경우 적합.
단점
반복적인 코드가 많음 → Connection, Statement, ResultSet을 직접 다뤄야 함.
SQL을 직접 관리해야 하므로 유지보수가 어려움.
객체-관계 매핑(ORM) 기능이 없음 → 엔티티 매핑을 직접 구현해야 함.
예제 코드
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db", "user", "password");
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM product WHERE id = ?");
pstmt.setLong(1, 1);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("name"));
}
rs.close();
pstmt.close();
conn.close();
2. MyBatis
특징
SQL을 XML 또는 어노테이션 기반으로 관리.
SQL을 직접 작성하지만, 객체 매핑을 지원.
JDBC보다 코드가 간결하며 자동 매핑 기능을 제공.
장점
- SQL을 직접 컨트롤 가능 → 복잡한 쿼리를 최적화할 수 있음.
- 객체 매핑 지원 → SQL 결과를 객체로 변환 가능.
- 자동 매핑 기능 → resultMap을 활용하여 엔티티 매핑 가능.
- JDBC보다 코드가 간결하고 유지보수가 쉬움.
단점
- SQL을 직접 관리해야 함 → 유지보수 부담 증가.
- 객체 지향적인 설계가 어려움 → SQL 중심 설계로 인해 객체 모델과 분리가 필요.
- 영속성 컨텍스트가 없음 → JPA의 변경 감지 기능을 사용할 수 없음.
예제 코드
<select id="findById" parameterType="long" resultType="Product">
SELECT * FROM product WHERE id = #{id}
</select>
Product product = productMapper.findById(1L);
3. JPA (Java Persistence API)
특징
• ORM(Object-Relational Mapping) 기반 기술.
• 객체 중심으로 데이터를 관리하고 자동으로 SQL을 생성.
• 트랜잭션과 영속성 컨텍스트를 통해 데이터 변경 사항을 자동 반영.
장점
- 객체 지향적인 개발 가능 → 엔티티 중심 설계가 가능.
- SQL 작성 없이 데이터 조작 가능 → 자동으로 SQL 생성.
- 트랜잭션 및 영속성 컨텍스트 관리 → Dirty Checking, 1차 캐시, Lazy Loading 지원.
- Spring Data JPA와 결합하면 CRUD가 매우 간단함.
- DB 벤더 종속성이 낮음 → JPQL, QueryDSL 등을 활용하면 특정 DB에 종속되지 않음.
- 내부적으로 PreparedStatement를 활용하기 때문에 바인딩 처리하여 SQLInjection 방지가능
단점
초기 학습 비용이 높음 → Hibernate의 내부 동작을 이해해야 함.
SQL을 직접 컨트롤하기 어려움 → 복잡한 쿼리는 QueryDSL과 함께 사용해야 함.
단순 조회 성능이 MyBatis보다 느릴 수 있음 → 최적화가 필요.
예제 코드
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByName(String name);
}
4. JPQL (Java Persistence Query Language)
특징
• JPA에서 제공하는 SQL과 유사한 쿼리 언어.
• 테이블이 아니라 엔티티 객체를 대상으로 쿼리를 실행.
• EntityManager.createQuery() 또는 @Query를 사용하여 실행.
장점
- SQL과 유사하여 배우기 쉬움.
- 데이터베이스 독립적 → 특정 DB에 종속되지 않음.
- 자동 변환 기능 제공 → 결과를 엔티티 객체로 매핑해줌.
단점
- 컴파일 시점에 문법 오류를 확인할 수 없음.
- 동적 쿼리 작성이 불편함 → QueryDSL보다 사용성이 떨어짐.
- 동적 쿼리 사용시 오류 발생 가능성이 높고 SQL Injection에 취약하다. 사용자가 입력한 데이터가 SQL문에 그대로 포함되기 때문이다.
예제 코드
public List<Product> findProducts(String name, Integer minPrice, Integer maxPrice) {
String jpql = "SELECT p FROM Product p WHERE 1=1";
if (name != null) {
jpql += " AND p.name = :name";
}
if (minPrice != null) {
jpql += " AND p.price >= :minPrice";
}
if (maxPrice != null) {
jpql += " AND p.price <= :maxPrice";
}
TypedQuery<Product> query = entityManager.createQuery(jpql, Product.class);
if (name != null) {
query.setParameter("name", name);
}
if (minPrice != null) {
query.setParameter("minPrice", minPrice);
}
if (maxPrice != null) {
query.setParameter("maxPrice", maxPrice);
}
return query.getResultList();
}
5. QueryDSL
특징
• JPQL을 타입 안전하게 사용할 수 있도록 지원.
• QClass를 활용하여 SQL-like한 코드로 쿼리 작성 가능.
• JPAQueryFactory를 사용하여 쿼리를 실행.
장점
컴파일 시점에 문법 오류를 체크할 수 있음 (타입 안전).
가독성이 높고 유지보수가 쉬움.
동적 쿼리를 편리하게 작성 가능.
페이징, 정렬 등 JPA와 결합하여 사용 가능.
내부적으로 PreparedStatement를 활용하기 때문에 바인딩 처리하여 SQLInjection 방지가능
단점
빌드 시 추가적인 코드 생성 과정(QClass)이 필요함.
JPQL보다 상대적으로 학습 비용이 높음.
예제 코드
QProduct p = QProduct.product;
List<Product> products = queryFactory
.selectFrom(p)
.where(p.name.eq("스마트폰"))
.fetch();
6. 비교 요약 표
비교 항목 | JDBC | MySQL | JPA | JPQL | QueryDSL |
쿼리 작성 방식 | SQL 직접 작성 | SQL(XML, 어노테이션) | ORM 기반 (SQL 자동 생성) | SQL 유사 | 코드 기반 DSL |
타입 안전성 | ❌ | ❌ | ✅ | ❌ | ✅ |
객체 매핑 | ❌ 수동 매핑 필요 | ✅ 자동 매핑 지원 | ✅ 엔티티 매핑 | ✅ 엔티티 매핑 | ✅ 엔티티 매핑 |
트랜잭션 관리 | 직접 처리 | 직접 처리 | 자동 처리 | 자동 처리 | 자동 처리 |
동적 쿼리 작성 | 불편 | 보통 | 어려움 | 어려움 | 편리 |
성능 | 가장 빠름 | 빠름 | 최적화 필요 | 최적화 필요 | 최적화 필요 |
복잡한 쿼리 지원 | 가능 | 매우 강력 | 보통 (QueryDSL 필요) | 가능하지만 불편 | 매우 강력 |
학습 난이도 | 쉬움 | 중간 | 높음 | 중간 | 중간 |
7. 결론 및 선택 기준
• JDBC → 가장 빠르지만 유지보수가 어려움. SQL을 직접 컨트롤해야 하는 경우 사용.
• MyBatis → SQL을 직접 사용하면서도 자동 매핑을 제공하여 유지보수가 용이함. 복잡한 쿼리가 많은 프로젝트에 적합.
• JPA → 객체 중심으로 데이터를 다룰 수 있으며, Spring Data JPA와 함께 사용하면 매우 편리함. 객체 지향적인 개발을 원한다면 선택.
• JPQL → SQL과 유사하지만 객체 지향적 접근이 가능. 기본적인 쿼리에 적합하지만 동적 쿼리는 QueryDSL이 더 좋음.
• QueryDSL → 타입 안전하며 동적 쿼리가 필요한 경우 가장 적합한 선택.
JPA를 사용하면 SQL을 직접 작성하지 않아도 되고, 유지보수성이 뛰어나지만 QueryDSL과 함께 사용하면 더욱 강력한 기능을 제공할 수 있다.
'Spring > JPA' 카테고리의 다른 글
[JPA, Kafka] @Transactional과 Kafka 메세지 전송 시점 (0) | 2025.03.09 |
---|---|
[JPA] @Transaction을 붙이지 않았을 때 생기는 문제, JPA Proxy, LazyLoading과 EagerLoading N+1 문제 (0) | 2025.02.22 |
[JPA] Soft Delete 개발 방법(Hard Delete과의 차이) (0) | 2025.02.17 |
[개념 정리]Spring Boot에서 JPA의 Soft Delete와 Cascade 연관관계 (1) | 2024.12.09 |
save the transient instance before flushing (1) | 2024.11.20 |