여는 글

안녕하세요. 오랜만에 포스팅입니다. 6개월 만이더라구요? 신입 개발자로서 정신없는 날들과 취업했다는 안정감을 가지니 블로그는 자연스레 뒤로 밀리게 된 것 같습니다. 오늘은 실무에서 느낀 점을 공유하려 하는데요, 취준생 시절과 현재의 관점 차이를 가장 크게 느낀 부분 중 하나가 바로 MyBatis와 JPA의 사용에 관한 것이었습니다.

입사 전에는 JPA가 신기술처럼 보였고(실제로는 등장한 지 꽤 오래됐지만), MyBatis는 복잡하고 비효율적인 구시대의 기술처럼 인식되었습니다. 이러한 선입견 때문인지, 저 역시 개인 포트폴리오 제작 시 JPA를 선호했죠.

오늘 포스팅에선 “MyBatis가 더 좋은 기술이다”라고 말하려는 것이 아니라, RDBMS를 사용할 때 MyBatis와 JPA 중 어떤 기술을 선택해야 할지 고민할 때 참고할 만한 기준점들을 공유하고자 합니다.

두 기술의 동작 방식 차이

MyBatis

MyBatis는 SQL Mapper Framework입니다. 개발자가 직접 SQL Query를 작성하여 데이터베이스와 통신하는 방식인데요. 아래의 예시처럼 XML 파일을 통해 쿼리를 작성하거나 어노테이션으로 SQL을 정의할 수 있습니다.

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User getUserById(int id);
}
<select>
  SELECT * FROM users WHERE id = #{id}
</select>

JPA

JPA는 Obejct Relational Mapping 기술입니다. 자바 객체와 데이터베이스를 자동으로 매핑하는 추상화 계층을 제공합니다. 데이터베이스와의 상호 작용을 객체 지향적으로 처리하기 때문에, SQL를 자동으로 생성하고 관리해서 SQL Query에대한 부담이 적습니다. 따라서 비즈니스 로직에 집중할수 있고, 코드의 가독성을 높일 수 있습니다.(MyBatis와는 비교도 안되게..)

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    ...
}

// JPA 리포지토리 인터페이스
public interface UserRepository extends JpaRepository<User, Long> {
}

두 기술 오해와 진실

1. MyBatis는 SQL Injection에 취약하다?

이는 틀린 얘기입니다. ORM 방식을 사용하면 기본적으로 PreparedStatement를 활용해 SQL Injection을 방어할 수 있습니다. GPT에게 SQL Injection 예방 방법을 물으면 ORM방식을 추천하기 때문에, 개발자 입장에서 MyBatis가 상대적으로 취약하다고 오해하기 쉽습니다.
하지만 MyBatis 역시 PreparedStatement를 사용할 수 있으며, SQL Injection에 대한 방어는 충분히 가능합니다. 결국, 보안의 문제는 기술 자체보다 개발자의 SQL, 코드 작성 방식에 달려 있습니다.

2. JPA는 SQL Query 작성이 필요 없다?

이는 절반은 맞고 절반은 틀린 주장입니다. JPA가 자동으로 쿼리를 생성하고 관리해 주지만, 복잡한 도메인 설계가 요구되는 상황에서는 JPQL을 사용해 직접 SQL 쿼리를 작성해야 하는 경우가 생깁니다.

특히, 다수의 조인, 특정 필터링 조건 등이 필요한 복잡한 쿼리에서는 JPA만으로는 한계가 있을 수 있어, 결과적으로 SQL 작성이 불가피한 상황이 발생할 수 있습니다.

3. MyBatis가 JPA보다 빠르다?

이는 진실입니다. 실제로 두 기술 속도에 대한 연구는 많이 이루어져 왔습니다. MyBatis가 JPA보다 최대 30% 더 높은 성능을 보인 연구결과가 있는데요. 이는 두 기술의 특정 CRUD를 비교했고, JPA가 엔티티 관리, 캐시 처리, 트랜잭션 등의 오버헤드가 존재함에 따라 더 느린 반응속도를 보였습니다. 여기에 더해 복잡한 조인, 필터링 조건이 있는 쿼리라면 MyBatis가 더 두각을 나타냅니다.

두 기술의 선택 기준

1. 대규모 트래픽 처리와 병렬성

대규모 데이터베이스 시스템에서는 트랜잭션의 효율적 관리와 병렬성을 확보하는 것이 필수적입니다. MyBatis와 JPA의 대규모 트래픽 처리와 병렬 처리에 관한 실험에 따르면, JPA는 기본적으로 트랜잭션 범위 내에서 멀티스레드 안정성을 보장하기 위해 EntityManager와 같은 구성 요소를 통해 동기화 메커니즘을 사용하는데, 이로 인해 데이터 일관성과 안정성이 보장되지만, 다수의 쓰레드가 동일한 엔티티에 접근할 때 Lock 경합이 발생할 수 있습니다.

예를 들어, @Transactional 경계를 설정할 때, 다수의 쓰레드가 같은 엔터티를 수정하려고 할 때 Optimistic Lock이나 Pessimistic Lock을 통해 상태 변경을 제어하는 방식으로 성능 병목이 발생할 수 있습니다. 반면, MyBatis는 다수의 쓰레드가 단순히 데이터베이스와 SQL을 통해 직접 통신하는 구조이기 때문에 동시성 제어가 필요 없는 경우 MyBatis가 더 나은 성능을 보일 수 있습니다.

2. 설계 복잡성과 코드 관리

지금까지의 내용들을 보면, MyBatis가 성능이 우월하니 MyBatis가 더 낫네 MyBatis 써야겠다. 하실 수 있지만, 저보다 더 똑똑한 개발자분들 더 좋은 회사들이 괜히 JPA를 쓰는 것이 아닙니다. 개발을 하는데에 있어서 오직 성능만이 고려되는것은 아닙니다. 개발에 참여하는 인적자원, 개발 속도, 유지보수성, 가독성 등 많은 요소들이 프로젝트에서 집약적으로 고려됩니다. 테이블, SQL Query그리고 Model Class를 생각했을때, MyBatis는 유연성이 매우 떨어집니다. 또한, 협업시 알 수 없는 쿼리의 목적, 조인문을 통한 쿼리, 떨어지는 가독성, SQL에 대한 이해도 요구, 디버깅의 어려움 등의 문제도 있고, 성능이 좋은 만큼 수동으로 세팅해줘야 하는 요소들이 많습니다.

따라서, JPA가 가지는 개발 생산성을 추구하면서 JPA가 가지는 단점을 보완하기 위한 연구가 많이 이루어지는 것입니다.

정리

기준 MyBatis JPA
데이터베이스 튜닝 및 최적화 세밀한 제어 가능 제한적
복잡한 쿼리 처리 직접 작성 JPQL 사용
개발 생산성 낮음 높음
성능 높음 상대적으로 낮음
대규모 트래픽 처리 유리 트랜잭션 병목 발생 가능
객체 지향 모델링 제한적 우수

결론

부트캠프나 학교에서 포트폴리오를 준비하는 개발자분들이 많을텐데요. 안그런 회사들도 매우 많지만(그냥 쓰던거 쓰자), 기술을 선택하고 사용할때 “왜”를 중요시하는 회사가 많습니다. JPA를 사용할 때도, MyBatis를 사용할 때도 왜 이 기술을 선택했는가에 대한 답을 명확히 준비하는 것이 중요합니다. 기술 선택의 기준을 명확히 하고, 본인의 프로젝트에 맞는 최적의 선택을 하시길 바랍니다.