이번에는 Spring MVC Architecture의 Model 부분과 관련된 Repository에 대해 알아 볼 것이다.
그 동안 모든 Component는 특정 어노테이션을 통해 IoC 컨테이너에 Bean으로 등록하고
어떤 Layer에서 사용 될 지 가시성 있게 표시하였다.
예를들면 @Controller 어노테이션을 통해
해당 IoC 컨테이너에 객체를 Bean으로 등록 및 Presentation Layer에서 사용될 Controller임을 명시하였다.
이처럼 그동안 어노테이션을 통해 각각 명시하였다.
그래서 Repository도 당연히 @Repository 어노테이션을 사용할 것이라고 생각 할 수 있다.
그러나 이번에 Repository를 구현함에 있어서 @Repository 어노테이션은 사용하지 않을 것이다.
그 이유는 Repository 구현으로 MyBatis 프로그램을 사용 할 것이기 때문이다.
우선 Repository가 무엇인지 먼저 정리하며 시작하겠다.
Repository란?
Service와 Domain을 연결 시켜주는 중간 다리 역할을 한다.
저번에 Service는 비즈니스 로직을 수행하는 Layer라고 했다.
Domain은 데이터베이스 Layer이다.
이때 Service와 Domain을 이어주는 객체가 Data Access Object 이다. (Data Access Object => DAO)
Repository는 DAO의 저장소라고 생각하면 좋겠다.
그동안 보통 DAO를 만들 때 아래와 같은 방식으로 만들었다.
1. Repository 인터페이스 생성
2. RepositoryImpl 클래스로 인터페이스 구현 (DAO 생성)
이와 같은 방식으로 할 때 RepositoryImpl에 @Repository 어노테이션을 붙여주기만 하면 된다.
그러나 이번엔 이처럼 DAO를 따로 생성하지 않고 MyBatis를 통해서 Repository의 역할을 대신 하게 할 것이다.
MyBatis
우선 MyBatis가 무엇인지에 대해 알아 보겠다.
MyBatis란?
관계형 데이터베이스 프로그래밍을 좀 더 쉽게 도와주는 Persistence Framework이다. (Persistence : 영속성 )
Persistance Frame의 대표적인 예로 SQL Mapper와 ORM이 있다.
MyBatis는 SQL Mapper로 SQL 쿼리와 비즈니스 코드(자바 소스코드)를 분리 할 수 있게 해준다. (sql 쿼리를 XML에 작성)
MyBatis를 사용하면 다음과 같은 이점을 얻을 수 있다.
1. 복잡한 쿼리나 다이나믹 쿼리에 유용하다.
2. 비즈니스 코드와 SQL쿼리를 분리 할 수 있게 해준다.
개인적인 여담인데, 그동안 위에서 사용했던 방법으로 DAO를 구현 했다.
예를들면 아래와 같은 방식으로 만들었었다.
String sql = "delete * from table";
pstmt.executeUpdate(sql);
그런데 친구가 코드 리뷰해줄 때
자바 코드 중간에 SQL 쿼리를 보기 싫으니 따로 함수로 따로 빼라고 했었다.
(근데 DAO는 쿼리가 반인데..?)
아무튼 그래서 지금 비즈니스 코드와 SQL 쿼리를 분리 할 수 있다는 것도 큰 장점으로 다가온다.
MyBatis를 통해 얻는 이점 2가지를 생각하며 MyBatis를 사용해 보겠다.
MyBatis 사용
이제 MyBatis를 사용해 볼 것이다.
우선 인터페이스를 정의해야 하는건 같다.
- 1. 인터페이스 정의
이처럼 인터페이스를 정의하고 @Mapper 어노테이션을 붙여줘야한다.
이때 @Mapper는 springfamework에 포함된 어노테이션은 아니다.
그런데 스프링 부트에서는 MyBatis Bean등록을 자동으로 해주니
MyBatis 사용을 위해서는 인터페이스에 @Mapper 어노테이션을 달아주기만 하면 된다.
save라는 추상 메소드를 하나 갖고있다.
해당 메소드는 Board 객체를 매개변수로 받는다.
- 2. 인터페이스 구현
위에서 MyBatis는 sql 쿼리를 XML에 작성한다고 했다.
해당 인터페이스 구현을 XML파일로 할 것이다.
resource/mappers 폴더 생성 후, 해당 폴더에 board.xml 파일을 추가했다.
해당 xml파일에 다음과 같은 줄을 추가한다.
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
그러면 이제 해당 xml파일은 인터페이스와 연결될 준비가 된 것이다.
이후에 <mapper></mapper> 태그 내부에 사용해 sql 쿼리를 정의한다.
그럼 이제 쿼리문을 작성하겠다.
우선 가장 기본적인 쿼리인 insesrt문을 작성하였다.
이제 코드를 설명하겠다.
mapper 태그
mapper 태그에는 namespace 속성 값으로 @Mapper 어노테이션이 달려있는 Repository의 reference를 주어야 한다.
아까 만들었던 BoardRepository 인터페이스이다.
이때 주의사항으로 namespace에 인터페이스의 reference를 주어야지 경로를 주면 안된다.
mapper 태그 내부엔 insert, select, update, delete 태그가 올 수 있다.
insert 태그
해당 예제에서는 mapper 태그 내부에 insert 태그가 있다.
우선 insert 태그의 속성으로 id, parameterType, resultType이 있다.
해당 예제에서는 resultType을 사용하진 않았지만 사용가능하다.
태그의 속성들을 알아보겠다. 일단 쿼리가 작동함에 가장 중요한 속성은 id이다.
id
예제를 보면 해당 insert문의 id는 "save"이다.
이는 Repository에서 작성했는 save() 추상 메소드이다.
id 값을 통해서 추상메소드를 구현한다. (연결한다)
parameterType
save 추상 메소드를 기억해보면 해당 메소드는
Board 객체를 매개변수로 받는다는 걸 알 수 있다.
parameterType에는 해당 객체의 reference를 주어야한다.
해당 예제의 입력 값은 Board 객체의 reference이다.
returnType
sql 쿼리문의 반환 값을 넘겨받을 때 객체의 type을 결정한다.
그런데 MyBatis에서는 insert 쿼리의 반환 값 type은
integer, long, boolean으로 기본으로 설정되어 있으므로
필요한 경우가 아니라면 건들이지 않는 것이 좋다.
추가적으로 returnType에도 클래스 객체로 넘겨 받으려면 reference를 주어야한다.
만약 String으로 받으려면 returnType=java.lang.String으로 해주어야 한다.
이제 Repository의 구현이 끝이났다.
요청 확인
저번에 Controller - Service - Repository - Domain의 연결이 이미 끝났다고 했다.
그래서 postman으로 요청을 보내면
이렇게 Client가 해당 url 요청을 하면 DB에 저장되는 것이다.
끝으로
MyBatis를 사용하니 여러모로 매우 편리하다.
진짜 인터페이스에 @Mapper 어노테이션 달아주고
xml 파일에 인터페이스 reference 잘 넣어주면
해당 xml파일에 sql 쿼리문 작성만 하면 되는 것이다.
사실 기존에도 DAO 구현이 복잡하다는 생각은 안해봤는데 (JDBC 노가다)
MyBatis 사용으로 DAO 구현이 이렇게 간단해질 줄 몰랐다.
사실 MyBatis는 되게 복잡한 일을 한다.
우선 SqlSession를 통해 mapping이 되고 SqlSession은 SqlSessionFactory 객체를 통해 생성된다.
둘 다 MyBatis에서 사용하는 객체이다.
그런데 이때 SqlSessionTemplate 객체를 이용해 코드에서 SqlSession을 또 대체한다.
그런데 사실 사용시에는 SqlSessionTemplate 같은건 몰라도 잘 작동하니 너무 좋다.
마지 이런게 프레임워크인가 싶다.
그래도 다음에 더 자세히 알아보긴 할 것이다.
앞으로 MyBatis를 무척 애용 할 거 같다.
로고도 귀엽다