백엔드 프로젝트를 개발하면서 가장 먼저 맞닥뜨리는 선택지 중 하나는 데이터베이스와 통신하는 방법을 정하는 일이다.
부트캠프 과정을 회고하면, 마이바티스 사용이 대부분이었다.
스프링 프로젝트의 공식 프로젝트인 펫클리닉 REST에서는 JPA방식을 사용하고 있다.
이 두 방법은 각각 장단점이 명확하게 다르기 때문에, 정리해보려고 한다.
1-1. JPA 방식 (Java Persistence API)
JPA는 표준 ORM(Object Relational Mapping)이다.
ORM? : Object-relational mapping(객체 관계 매핑), 객체는 객체대로, db는 db대로 설계, orm 프레임워크가 매핑.
Entity(클래스)와 테이블을 연결해서 DB를 객체처럼 다룰 수 있도록 해준다.
- Entity 클래스를 기반으로 SQL을 자동 생성하거나 실행할 수 있다.
- JPQL이라는 객체 지향 쿼리 언어를 사용한다.
- 복잡한 조인이나 최적화 쿼리는 따로 튜닝해야 한다.
장점:
- 개발자가 직접 SQL을 작성할 일이 적어진다.
- 유지보수성, 코드 일관성이 높다.
- 트랜잭션, 캐시 관리 등을 일관성 있게 처리할 수 있다.
단점:
- 학습 비용이 높다. (영속성 컨텍스트, 지연로딩 등 개념 이해 필요)
- 내부 동작을 모르면 디버깅이 어려울 수 있다.
- 복잡한 쿼리는 오히려 비효율이 생길 수 있다.
@Entity
@Table(name = "owners")
public class Owner extends Person {
@Column(name = "address")
private String address;
@Column(name = "city")
private String city;
@Column(name = "telephone")
private String telephone;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets = new HashSet<>();
// getters and setters 생략
}
펫클리닉 REST 버전(PetClinic REST API)의 일부
- @Entity: 이 클래스가 DB 테이블과 매핑되는 JPA 엔티티라는 뜻.
- @Table(name = "owners"): DB의 owners 테이블과 매핑하겠다는 뜻.
- @Column(name = "address"): 필드를 DB의 address 컬럼과 연결.
- @OneToMany: Owner 한 명이 여러 Pet을 가질 수 있다는 관계 설정.
객체 자체를 테이블과 매핑하는 느낌.
CRUD같은 기본 작업은 JPA의 메서드가 알아서 해 줘서 편한데, ( save(), findById()) 조인이나 서브쿼리를 쓰게 되면 학습 난이도가 올라간다.
1-2. MyBatis 방식
MyBatis는 SQL을 직접 작성하는 방식의 데이터 매핑 프레임워크다. ORM은 아니고, SQL Mapper라고 부른다.
- SQL을 XML 파일이나 어노테이션에 명시적으로 작성한다.
- 복잡한 쿼리도 개발자가 자유롭게 튜닝할 수 있다.
- 객체 매핑은 수동으로 매핑 규칙을 설정해줘야 한다.
장점:
- SQL 최적화나 튜닝이 쉬운 편이다.
- 쿼리 구조를 명확하게 컨트롤할 수 있다.
- 복잡한 비즈니스 로직(DB 레벨) 처리가 편하다.
단점:
- 쿼리가 많아질수록 코드 관리가 어려워질 수 있다.
- SQL이 하드코딩 -> 유지보수 시 실수가 늘어날 수 있다.
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE email = #{email}")
Optional<User> findByEmail(String email);
@Insert("INSERT INTO users (email, password, name) VALUES (#{email}, #{password}, #{name})")
void insertUser(User user);
@Update("UPDATE users SET password = #{password}, name = #{name} WHERE email = #{email}")
void updateUser(User user);
@Delete("DELETE FROM users WHERE email = #{email}")
void deleteUser(String email);
}
- @Mapper: 이 인터페이스가 MyBatis 매퍼임을 명시.
- 각 메서드마다 직접 SQL을 작성해서 DB 작업을 수행.
- #{} 문법으로 파라미터를 직접 바인딩.
- CRUD 모두 명시적으로 SQL이 필요.
직접 SELECT 구문을 적어주고, 파라미터 바인딩도 명시적으로 처리해야 한다.
주의 : 파라미터를 받을때 ${파라미터} 방식을 쓰면 인젝션 공격에 취약함. (값이 그대로 SQL에 삽입될 수 있음)
결론적으로,
- 단순한 CRUD + 규칙적인 구조 → JPA
- 복잡한 비즈니스 로직, 최적화 중심 → MyBatis
- 지금까지는, 사용하기 쉬운 쪽은 마이바티스인 것 같다.(어노테이션이 알아서 해줌...)
'백엔드' 카테고리의 다른 글
| 디스패처 서블릿이란? (1) | 2026.02.14 |
|---|---|
| 배포 연습 서버로 Ubuntu를 선택한 이유 (0) | 2025.04.27 |