[Spring] JPA와 MyBatis의 차이점, 그리고 Stored Procedure
1. 들어가며
지금까지 Spring Boot 기반의 백엔드 프로젝트를 개발하면서 주로 Spring Data JPA를 사용했다.
Entity를 정의하고 Repository 인터페이스를 작성하면 기본적인 CRUD를 처리할 수 있었고, 복잡한 조회는 JPQL이나 QueryDSL을 활용했다.
그러다 최근 입사한 회사 업무에서 SQL을 직접 작성하고 실행하는 MyBatis와 데이터베이스 내부에 로직을 정의하는 Stored Procedure(SP)에 대해 알게되었다.
JPA에서는 객체를 중심으로 데이터에 접근했다면, MyBatis에서는 SQL 자체가 데이터 접근 계층의 핵심이 된다.
처음에는 JPA가 더 편리한데 왜 MyBatis를 사용하는지 궁금했다. 하지만 두 기술은 단순히 편의성의 차이가 아니라 데이터 접근 방식과 설계 철학에 차이가 있다는 것을 알게 되었다.
이번 글에서는 다음 내용을 정리한다.
- MyBatis란 무엇인가?
- JPA와 MyBatis는 어떤 차이가 있는가?
- MyBatis는 어떤 상황에서 유리한가?
- Stored Procedure는 무엇이며 어떻게 연동하는가?
- 데이터 접근 기술을 선택할 때 고려해야 할 트레이드오프는 무엇인가?
2. MyBatis란?
MyBatis는 개발자가 작성한 SQL을 실행하고 그 결과를 Java 객체로 매핑해 주는 SQL Mapper 프레임워크다.
JPA가 객체와 관계형 데이터베이스의 매핑 및 영속성 관리를 중심으로 동작한다면, MyBatis는 SQL 실행과 결과 매핑에 초점을 맞춘다.
JPA 방식
public interface UserRepository
extends JpaRepository<User, Long> {
}
User user = userRepository.findById(1L)
.orElseThrow();
Spring Data JPA는 기본적인 CRUD 메서드를 제공하고, JPA 구현체가 필요한 SQL을 생성한다.
MyBatis 방식
@Mapper
public interface UserMapper {
User findById(@Param("id") Long id);
}
<select id="findById"
resultType="com.example.dto.User">
SELECT id, name
FROM users
WHERE id = #{id}
</select>
MyBatis에서는 개발자가 SQL을 직접 정의한다.
이때 #{id}는 JDBC의 PreparedStatement 파라미터 바인딩을 통해 처리된다.
핵심은 JPA가 객체의 영속성 관리까지 담당하는 ORM 기술인 반면, MyBatis는 SQL 실행과 결과 매핑을 담당한다는 점이다.
3. JPA와 MyBatis의 차이
| 구분 | JPA | MyBatis |
| 접근 방식 | ORM | SQL Mapper |
| 중심 요소 | Entity | SQL |
| 기본 CRUD | 자동 생성 가능 | 직접 SQL 정의 |
| 변경 감지 | 지원 | 지원하지 않음 |
| 영속성 컨텍스트 | 존재 | 존재하지 않음 |
| 복잡한 쿼리 | JPQL, QueryDSL, Native SQL | SQL 직접 작성 |
| 캐시 | 영속성 컨텍스트 1차 캐시 | SqlSession 로컬 캐시 |
| SP 연동 | 가능 | CALLABLE 지원 |
영속성 컨텍스트의 차이
JPA에서는 영속 상태의 Entity를 변경하면 Dirty Checking을 통해 데이터베이스에 변경 사항을 반영할 수 있다.
@Transactional
public void changeName(Long id) {
User user = userRepository.findById(id)
.orElseThrow();
user.changeName("Kim");
}
반면 MyBatis에서는 UPDATE SQL을 명시적으로 실행해야 한다.
@Transactional
public void changeName(Long id) {
userMapper.updateName(id, "Kim");
}
이 차이는 단순히 코드 작성량의 차이가 아니다.
JPA에서는 Entity의 상태 변화가 중요한 반면, MyBatis에서는 어떤 SQL을 언제 실행할 것인지가 명확하게 드러난다.
4. MyBatis를 사용하는 이유
4.1 SQL을 명시적으로 관리할 수 있다
복잡한 JOIN이나 데이터베이스 전용 함수가 필요한 경우 SQL을 직접 작성하고 관리할 수 있다.
4.2 기존 데이터베이스 구조를 활용하기 쉽다
이미 정의된 테이블, SQL, Stored Procedure를 유지하면서 Java 애플리케이션과 연동하기에 적합하다.
4.3 SQL 튜닝 과정이 직접적이다
실행할 SQL이 명시되어 있으므로 실행 계획을 확인하거나 쿼리를 수정하기 편리할 수 있다.
다만 MyBatis가 JPA보다 무조건 빠른 것은 아니다.
실제 성능은 SQL의 품질, 인덱스, 실행 계획, 데이터 규모, 트랜잭션 설계 등에 따라 달라진다.
5. Stored Procedure(SP)란?
Stored Procedure는 데이터베이스 내부에 저장된 SQL 및 절차적 로직의 집합이다.
예를 들어 주문 상태를 변경하는 작업을 데이터베이스에 프로시저로 정의할 수 있다.
다음은 MySQL 기준 예시다.
DELIMITER //
CREATE PROCEDURE update_order_status(
IN p_order_id BIGINT,
IN p_status VARCHAR(30)
)
BEGIN
UPDATE orders
SET order_status = p_status
WHERE order_id = p_order_id;
END //
DELIMITER ;
호출할 때는 다음과 같이 사용한다.
CALL update_order_status(100, 'COMPLETED');
이 방식은 SQL 로직을 애플리케이션 외부의 데이터베이스에 정의한다는 특징이 있다.
MyBatis에서 SP 호출하기
<update id="updateOrderStatus"
statementType="CALLABLE">
{ CALL update_order_status(
#{orderId, mode=IN, jdbcType=BIGINT},
#{status, mode=IN, jdbcType=VARCHAR}
) }
</update>
MyBatis는 JDBC를 통해 프로시저를 호출하고, 실제 로직은 데이터베이스에서 실행된다.
Controller
|
Service
|
MyBatis Mapper
|
JDBC
|
Database
|
Stored Procedure
따라서 MyBatis와 SP는 같은 기술이 아니다.
MyBatis는 애플리케이션의 데이터 접근 프레임워크이고, SP는 데이터베이스 내부에서 실행되는 프로그램이다.
6. Stored Procedure의 장단점
| 장점 | 단점 |
| 1. 공통 로직 재사용 여러 애플리케이션에서 동일한 데이터 처리 로직을 호출할 수 있다. |
1. 비즈니스 로직 분산 Java Service와 데이터베이스 SP에 로직이 나뉘면 전체 흐름을 파악하기 어려워질 수 있다. |
| 2. 데이터베이스 중심 처리 복잡한 데이터 변경 로직을 데이터베이스 내부에 구현할 수 있다. |
2. 데이터베이스 종속성 DBMS별 프로시저 문법과 동작 차이로 인해 데이터베이스 변경이 어려워질 수 있다. |
| 3. 기존 SQL 자산 활용 기존에 작성된 프로시저를 재사용하면서 애플리케이션을 개발할 수 있다. |
3. 테스트 및 배포 복잡성 프로시저 변경과 애플리케이션 변경의 호환성을 검증하고 데이터베이스 로직도 버전 관리해야 한다. |
7. JPA와 MyBatis 중 무엇을 선택해야 할까?
두 기술은 어느 하나가 항상 우수하다고 판단하기 어렵다.
JPA는 객체 중심의 도메인 모델과 영속성 관리가 중요한 환경에서 유리하다.
MyBatis는 SQL을 명시적으로 관리해야 하거나 기존 데이터베이스 구조 및 프로시저와의 연동이 중요한 환경에서 유리할 수 있다.
또한 하나의 애플리케이션에서 JPA와 MyBatis를 함께 사용하는 것도 가능하다.
예를 들어 일반적인 CRUD는 JPA로 처리하고, 복잡한 조회나 기존 SQL 연동은 MyBatis로 처리할 수 있다.
다만 두 기술을 함께 사용한다면 영속성 컨텍스트와 직접 SQL 실행 사이의 데이터 일관성, flush 시점, 트랜잭션 경계 등을 주의해야 한다.
결국 중요한 것은 프레임워크의 인기도나 코드 작성량이 아니라 데이터 접근 요구사항에 적합한 기술을 선택하는 것이다.
8. 마무리
JPA와 MyBatis를 비교하면서 가장 크게 느낀 점은 데이터 접근 기술에 따라 애플리케이션을 설계하는 관점이 달라진다는 것이다.
JPA는 객체와 영속성 관리를 중심으로 개발할 수 있도록 돕는다.
반면 MyBatis는 SQL을 직접 제어하고 데이터베이스 중심의 처리를 명시적으로 관리할 수 있게 한다.
Stored Procedure 역시 공통 데이터 처리 로직을 재사용할 수 있다는 장점이 있지만, 로직이 데이터베이스 내부에 위치한다는 점에서 유지보수와 테스트에 대한 추가적인 고려가 필요하다.
이번 학습을 통해 기술 선택에는 항상 트레이드오프가 존재한다는 점을 다시 확인했다.
데이터 접근 기술을 선택할 때 중요한 것은 어떤 기술이 더 최신인지가 아니라, 시스템의 요구사항과 제약 조건에 어떤 기술이 더 적합한지를 판단하는 것이다.
추가로 공부할 내용
- MyBatis의 동적 SQL과 ResultMap
- MyBatis의 1차·2차 캐시 동작 방식
- Spring
@Transactional과 Stored Procedure의 트랜잭션 경계 - JPA와 MyBatis를 함께 사용할 때의 데이터 일관성 문제
참고 자료
'개발 공부 > Java' 카테고리의 다른 글
| [Spring AI] LLM을 백엔드 서비스에 연결하기 - ChatClient와 컨텍스트 (0) | 2026.08.24 |
|---|---|
| [TIL] 장애 대응 (0) | 2026.08.21 |
| [TIL] 모니터링 시스템 및 시큐어 코딩 (0) | 2026.08.21 |
| [TIL] 대규모 시스템 설계 기초 (0) | 2026.07.28 |
| [TIL] Redis 자료구조와 캐싱(Cache) (0) | 2026.07.28 |
