MyBatis의 데이터 베이스 접근 흐름은 다음과 같다.
controller -> Service -> mapper 인터페이스 -> xml 파일 방식 혹은 어노테이션 방식
이 중 어노테이션 방식은 따로 xml 처럼 파일을 만드는 것이 아니라,
mapper 인터페이스에 어노테이션을 붙혀서 sql을 작성하는 것이다.
나는 JPA를 써본 입장에서 이것은 JPA 의 reposiroty에서 @Query 방식과 매우 흡사하다는 것을 발견했다.
고로 나의 질문은 다음과 같다.
그럼 이 둘의 차이점은 무엇이고?
언제 무엇을 써야 하는 것인가?
둘다 Query Language를 사용해야 하는 것에 대한 공통점이 있지만,
세부 차이점은 다음과 같이 있다.

쿼리 언어가 세가지나 있다.
이것에 대한 비교는 다음에 따로 정리를 해보도록 하자!!!
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// JPQL 방식
@Query("SELECT u FROM User u WHERE u.username = :username")
User findByUsername(@Param("username") String username);
// 네이티브 SQL 방식
@Query(value = "SELECT * FROM users WHERE username = :username", nativeQuery = true)
User findByUsernameNative(@Param("username") String username);
}
특징 요약
:username은 바인딩 변수로, 메서드 파라미터와 매핑됩니다.
JPQL 방식은 엔티티 필드 이름(username)을 기준으로 작동합니다.
네이티브 SQL은 데이터베이스 테이블과 컬럼 이름을 직접 참조합니다.
@Mapper
public interface UserMapper {
// SQL 직접 작성
@Select("SELECT * FROM users WHERE username = #{username}")
User findByUsername(@Param("username") String username);
}
특징 요약
#{username}은 SQL 바인딩 변수로 사용됩니다.
SQL을 직접 작성하므로 데이터베이스 컬럼 이름과 테이블 구조에 의존적입니다.
복잡한 동적 쿼리는 XML 방식으로 처리하는 것이 일반적입니다.
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// JPQL로 작성
@Query("SELECT u FROM User u WHERE u.username = :username")
User findByUsername(@Param("username") String username);
}
@Mapper
public interface UserMapper {
// 순수 SQL로 작성
@Select("SELECT * FROM users WHERE username = #{username}")
User findByUsername(@Param("username") String username);
}
둘다 어노테이션 + 쿼리 문이기에 크게 달라 보일 것은 없지만,
sql문에 익숙한 개발자는 mybatis의 순수 sql문이 좀 더 편하지 않을까 싶다.
엔티티 중심의 설계를 따르고 싶을 때.
ORM의 이점을 최대한 활용하려는 경우.
복잡하지 않은 쿼리 작업을 주로 수행하는 경우.
SQL 중심의 설계를 선호하거나, 데이터베이스에 최적화된 쿼리가 필요한 경우.
복잡하고 동적인 쿼리가 많은 경우(XML 방식과 병행).
SQL의 자유도가 중요한 프로젝트.
가능은 하다.
하지만 언제 무엇을 쓰는지에 대한 팀원들간의 명확한 규정이 없으면 너무 프로젝트가 복잡해질 수도 있다.
그래서 예를 들어 다음과 같이 규정을 정하고 들어가야 한다고 한다.
간단한 작업: JPA 혹은 JPA @Query로 처리.
약간 복잡한 SQL: MyBatis 애너테이션 방식으로 처리.
매우 복잡한 동적 SQL: MyBatis XML 방식으로 처리.