- ···
- 22.
[멀티캠퍼스] 풀스택 개발자 아카데미 (22) - Spring Framework(2) - 23.[멀티캠퍼스] 풀스택 개발자 아카데미 (23) - Spring Framework(3)현재
- 24.
[멀티캠퍼스] 풀스택 개발자 아카데미 (24) - Spring Framework(4) - ···
1. JDBC의 반복 작업
이전 글에서는 Spring MVC의 핵심인 DispatcherServlet의 동작 방식과 요청 처리 흐름을 살펴보았다. @Controller와 @RequestMapping을 통해 웹 요청을 처리하고, web.xml과 servlet-context.xml로 기본적인 설정을 구성하는 방법을 익혔다. 이제 웹 애플리케이션의 필수 요소인 데이터베이스 연동 부분을 Spring MVC 환경에 맞게 개선할 차례이다.
지금까지 DAO(Data Access Object)에서 순수 JDBC API를 사용하여 DB 작업을 수행했다. JDBC는 자바에서 DB에 접근하는 표준 방법이지만, Connection 생성, PreparedStatement 준비, ResultSet 처리, 자원 반납 등 반복적이고 장황한 코드(Boilerplate code)를 매번 작성해야 하는 불편함이 있다. 또한, SQL 쿼리가 자바 코드 내부에 문자열 형태로 섞여 있어 가독성이 떨어지고 유지보수가 어렵다는 단점도 존재한다.
이번 글에서는 이러한 JDBC의 단점을 효과적으로 개선해주는 MyBatis 프레임워크를 소개한다. MyBatis가 어떻게 SQL 중심의 개발을 지원하며 생산성을 높여주는지 알아보고, Spring MVC 프로젝트에 MyBatis를 연동하기 위한 의존성 추가, XML 설정(root-context.xml), 그리고 Mapper 인터페이스와 XML 파일을 분리하여 SQL을 관리하는 방법을 구체적인 예제와 함께 살펴본다. 마지막으로 @Service, @Repository 어노테이션을 활용한 계층형 구조 설계의 중요성도 함께 다룬다.
2. MyBatis와 SQL Mapper
MyBatis는 개발자가 지정한 SQL, 저장 프로시저 그리고 고급 매핑을 지원하는 SQL Mapper 프레임워크이다. ORM(Object-Relational Mapping) 프레임워크로 분류되기도 하지만, 객체와 관계형 데이터베이스 테이블 간의 완전한 자동 매핑을 추구하는 JPA/Hibernate와는 달리, SQL 쿼리를 XML 파일에 분리하여 작성하고, 이 SQL의 실행 결과와 자바 객체(주로 VO/DTO)를 매핑해주는 역할에 더 집중한다.
MyBatis는 SQL 쿼리 결과(테이블의 Row)를 개발자가 정의한 자바 객체(VO/DTO)로 자동으로 옮겨 담아준다.
MyBatis를 사용하면 다음과 같은 장점을 얻을 수 있다:
- SQL 분리: 복잡한 SQL 쿼리를 자바 코드에서 완전히 분리하여 XML 파일에서 관리하므로, SQL 수정이 용이하고 가독성이 향상된다.
- 반복 코드 제거: JDBC API의 번거로운 준비 및 자원 해제 코드를 MyBatis가 대신 처리해주어 개발자는 SQL 작성과 결과 매핑에만 집중할 수 있다.
- 유연한 동적 SQL: XML 내에서 조건문(
if), 반복문(foreach) 등을 사용하여 상황에 따라 SQL 구문을 동적으로 변경할 수 있어 강력하고 유연한 쿼리 작성이 가능하다. - 매핑 자동화: SQL 실행 결과를 자바 객체(VO/DTO)의 필드에 자동으로 매핑해주는 기능을 제공한다.
- DAO 인터페이스 지원: DAO 구현 클래스를 직접 만들 필요 없이, 인터페이스(Mapper)만 정의하면 MyBatis가 내부적으로 구현체를 생성하여 연결해준다.
3. Spring MVC 프로젝트와 MyBatis 연동
이제 STS 3.9 (IntelliJ IDEA + Spring Legacy Project) 기반의 프로젝트에 MyBatis를 연동하는 과정을 단계별로 살펴보자.
3.1. pom.xml: 필요한 라이브러리 추가
MyBatis와 Spring 연동을 위해서는 몇 가지 라이브러리가 필요하다. pom.xml 파일의 <dependencies> 섹션에 다음 의존성들을 추가한다. (버전은 프로젝트 환경 및 Spring 버전에 맞춰 최신 안정 버전을 사용하는 것이 좋다.)
XML
pom.xml 파일을 수정한 후에는 Maven 프로젝트를 업데이트하여 라이브러리들을 다운로드 받아야 한다. (IntelliJ IDEA의 Maven Tool Window에서 Reload)
3.2. root-context.xml: 핵심 빈(Bean) 설정
root-context.xml 파일(또는 별도의 DB 설정 XML 파일)에 MyBatis 연동에 필요한 핵심 빈들을 등록한다. 이 파일은 웹 계층(servlet-context.xml)이 아닌 비즈니스 로직 및 데이터 계층에서 공통으로 사용될 빈들을 정의하는 곳이다.
XML
주요 설정 설명:
dataSource: 이전 편에서 배운 커넥션 풀(DBCP2 또는 HikariCP) 빈을 정의한다. DB 접속 정보를 여기에 설정한다.jdbc.properties파일을 분리하여 사용할 수도 있다.sqlSessionFactory: MyBatis의 핵심 객체인SqlSessionFactory를 생성하는 빈이다.DataSource를 참조하고, Mapper XML 파일들의 위치를 지정하는 것이 중요하다 (mapperLocations).typeAliasesPackage는 VO 클래스의 전체 경로 대신 짧은 별칭을 사용할 수 있게 해준다.sqlSession:SqlSessionTemplate은SqlSession을 스프링 빈으로 사용할 수 있게 해주며, 스레드 환경에서 안전하게 DB 작업을 수행하도록 돕는다.<mybatis-spring:scan>: 지정된base-package아래에 있는 Mapper 인터페이스들을 찾아서 스프링 빈으로 자동 등록해준다. 이를 통해@Autowired로 Mapper 인터페이스를 주입받아 사용할 수 있게 된다.
3.3. Mapper 인터페이스와 XML 파일 분리
MyBatis의 가장 큰 장점 중 하나는 SQL을 XML 파일에 분리하여 관리하는 것이다. 이를 위해 Mapper 인터페이스와 Mapper XML 파일을 쌍으로 만든다.
1. Mapper 인터페이스 생성 (ProductMapper.java)
DB 작업을 위한 메소드들을 정의하는 인터페이스를 만든다. 보통 src/main/java 아래의 mapper 또는 dao 패키지에 위치시킨다.
Java
2. Mapper XML 파일 생성 (ProductMapper.xml)
Mapper 인터페이스의 각 메소드에 해당하는 실제 SQL 쿼리를 작성하는 XML 파일을 만든다. src/main/resources 아래의 mappers 디렉터리(또는 sqlSessionFactory의 mapperLocations에 지정된 경로)에 위치시킨다.
XML
핵심 규칙:
- Mapper XML 파일의
namespace속성값은 해당 인터페이스의 전체 경로와 정확히 일치해야 한다. <select>,<insert>,<update>,<delete>태그의id속성값은 인터페이스의 메소드 이름과 정확히 일치해야 한다.resultType은 조회 결과(SELECT)를 매핑할 자바 객체 타입을 지정한다.parameterType은 SQL 실행 시 전달받을 파라미터의 타입을 지정한다.#{...}구문은 전달된 파라미터 값을 안전하게 SQL에 바인딩하는 역할을 한다 (PreparedStatement의?와 유사). 파라미터가 VO 객체일 경우#{필드명}으로 객체의 프로퍼티에 접근할 수 있다.
![MyBatis-파라미터-바인딩-#
4. Service와 Repository
Spring 애플리케이션은 일반적으로 다음과 같은 계층형 구조로 설계된다.
Controller → Service → Repository(DAO) → Mapper(MyBatis)
- Controller: 웹 요청 처리 및 응답,
Service계층 호출 - Service: 비즈니스 로직(트랜잭션 처리 등) 담당,
Repository계층 호출 - Repository (DAO): 데이터베이스 접근 로직 담당, MyBatis Mapper 인터페이스 호출
Spring은 각 계층의 역할을 명확히 하고 빈으로 관리하기 위해 다음과 같은 어노테이션을 제공한다 (@Component의 특수화 버전).
@Service: 비즈니스 로직을 처리하는 서비스 계층의 클래스에 사용한다.@Repository: 데이터 접근(DB 연동)을 담당하는 DAO 또는 Repository 계층의 클래스에 사용한다. Spring은 이 어노테이션이 붙은 클래스에서 발생하는 DB 관련 예외를 Spring의DataAccessException으로 변환해주는 기능도 제공한다.
이 어노테이션들을 사용하고 <context:component-scan>을 설정하면, 해당 클래스들이 자동으로 스프링 빈으로 등록된다. 그리고 @Autowired를 사용하여 각 계층 간의 의존성을 주입받을 수 있다.
Service 클래스 예시 (ProductService.java):
Java
Controller에서 Service 주입 및 사용 예시:
Java
이제 Controller는 Service에, Service는 Mapper에 의존하며 각자의 역할에만 충실하게 된다.
5. 마무리하며: SQL 중심 개발의 편리함
이번 7편에서는 JDBC의 번거로움을 해결하고 SQL 중심의 개발을 가능하게 하는 MyBatis 프레임워크를 Spring MVC와 연동하는 방법을 상세히 알아보았다. pom.xml 의존성 추가부터 root-context.xml 빈 설정, 그리고 Mapper 인터페이스와 XML 파일을 분리하여 SQL을 관리하는 핵심 과정까지 실습을 통해 익혔다. @Service, @Repository를 이용한 계층형 구조 설계는 코드의 역할 분담을 명확히 하여 유지보수성을 높이는 중요한 요소임을 확인했다.
MyBatis를 사용함으로써 개발자는 반복적인 JDBC 코드 작성에서 해방되고, 분리된 XML 파일에서 SQL을 보다 편리하게 관리하고 최적화할 수 있게 되었다. 이는 특히 복잡한 SQL 쿼리가 많은 프로젝트에서 생산성을 크게 향상시킨다.
물론 MyBatis 외에도 JPA(Java Persistence API)와 같은 ORM 기술도 널리 사용되지만, 기존 SQL에 익숙하거나 SQL 중심의 세밀한 제어가 필요한 경우 MyBatis는 여전히 강력하고 매력적인 선택지이다.
다음 8편에서는 Spring MVC를 사용하여 RESTful 웹 서비스를 구축하는 방법과, 화면 전환 없이 서버와 통신하는 Ajax 기술을 jQuery와 함께 활용하는 방법을 알아본다. 또한, 반복적인 VO/DTO 코드를 줄여주는 Lombok 라이브러리 도입에 대해서도 살펴볼 것이다.
6. 평가
MyBatis는 SQL을 직접 제어하면서도 JDBC의 번거로움을 크게 줄여주는 실용적인 데이터 매퍼 프레임워크이다. SQL 분리를 통해 개발자와 DBA(데이터베이스 관리자) 간의 협업을 용이하게 하고, 동적 SQL 기능은 복잡한 조회 조건을 유연하게 처리할 수 있도록 돕는다. Spring과의 연동 설정은 XML 기반으로 다소 장황해 보일 수 있으나, <mybatis-spring:scan>과 같은 기능을 통해 비교적 간편하게 Mapper 인터페이스를 빈으로 등록하고 사용할 수 있다. 계층형 구조 설계는 Spring 애플리케이션의 기본이며, 각 어노테이션의 의미와 역할을 이해하는 것이 중요하다. XML 설정 파일(root-context.xml)의 각 빈(DataSource, SqlSessionFactoryBean, SqlSessionTemplate)이 어떤 역할을 하는지 정확히 파악하는 것이 MyBatis 연동의 핵심이다.