Mybatis는 데이터베이스로부터 직접 SQL문으로 데이터를 가져오고 객체(Entity든지, DTO든지, VO든지)에 반영하여 사용하도록 해주는 데이터베이스 접근 프레임워크이다.
이번에 Spring boot에서 Mybatis를 사용해본다.
Spring MVC 클래스(Controller, Service, Entity 등) 가 준비된 상태에서 Mybatis 기능을 추가하여 사용하는 방식으로 설명한다.
위 그림과 같이 build.gradle 파일에 의존성을 추가한다.
resources 디렉토리 내 application.yml 설정파일에
mybatis:
mapper-location: classpath:mapper/*.xml
을 입력한다.
이는 resources/.../mapper 라는 디렉토리 안의 모든 xml파일은 mybatis의 매핑 xml파일로 인식하겠다는 의미이다.
※ mybatis.configuration.log-impl 이나 logging.level.com.posting.mybatisCategory.mapper 내용은 콘솔에 로그를 확인할 경우 사용한다.
나중에 SQL 파라미터나 결과데이터로 받게 될 객체클래스를 생성한다.
위와 같이 @Mapper 애너테이션을 사용하여 Mybatis Mapper 인터페이스를 생성한다.
여기서는 데이터요청에 사용되는 메서드 시그니처를 선언한다.
파라미터로 사용할 변수나 객체를 선언하고 리턴받을 타입을 선언한다.
※ Mapstruct를 사용할 경우 @Mapper가 서로 다르니
org.apache.ibatis.annotations.Mapper의 Mapper를 사용한다.
※ 파라미터가 객체가 아닌 특정 변수로 받을 경우 위와 같이 @Param을 사용한다.
비즈니스 역할 클래스에 위에서 만든 Mapper Interface 을 의존성 주입한다.
보통은 서비스 클래스에서 비즈니스 역할을 수행하므로 서비스 클래스에 의존성 주입 을 하였다.
서비스클래스의 메서드에서 각 역할에 맞게 Mapper Interface의 메서드를 호출한다.
실질적으로 데이터베이스로부터 SQL문으로 데이터를 받아올 XML파일을 생성한다.
Mapper Interface에서 선언해뒀던 메서드에 대한 SQL문을 작성한다.
※ 특정 위치가 반복될 경우 아래처럼 alias를 선언하고 사용할 수 있다.
...
<typeAliases>
<typeAlias type="com.posting.mybatisCategory.entity.MybatisCategory" alias="CategoryAlias"/>
</typeAliases>
<select id="findCategories" resultType="CategoryAlias">
SELECT category_id as categoryId, category_name as categoryName
FROM category
</select>
...
위의 데이터를 기반으로 간단한 CRUD 예제를 작성한다.
요청을 받을 Controller 메서드를 작성한다.
파라미터로 Id 값을 받기로 한다.
Controller에서 호출되는 Service 메서드를 작성한다.
이어서 Service 메서드에서 호출될 Mapper 메서드를 작성한다.
파라미터로 Id값을 사용하므로 @Param("categoryId") long categoryId 를 선언한다.
Mapper Interface에서 선언한 메서드에 대한 SQL문을 작성한다.
GET 요청에 맞춰 Select 문을 작성한다.
@Param에 선언했던 파라미터 categoryId를 where 에 사용한다.
그리고 결과데이터를 MybatisCategory 객체에 닮아보낸다.
select 문을 보면 category_id as categoryId, category_name as categoryName 식으로 적었는데, 데이터베이스 category 테이블의 컬럼명은 category_id, category_name 이고, MybatisCategory 클래스의 멤버명은 categoryId, categoryName 이기에 select문에서 컬럼명을 멤버명으로 바꾸어 요청했다.
이렇게 포스트맨으로 요청을 하면 파라미터에 맞춰서 결과를 볼 수 있다.
포스트맨 요청시 나타난 콘솔내용을 보면 위와 같다.
List 데이터를 받을 Controller 메서드를 작성한다.
Service 메서드를 작성한다
Service 메서드에서 호출될 Mapper 메서드를 선언한다.
Mapper Interface에서 선언한 메서드를 Mapper.xml에서 작성한다.
resultType에는 데이터를 받을 객체위치를 적는다.
이렇게 포스트맨으로 실행하면 List 결과가 나온다.
포스트맨 요청시 콘솔 내용은 위와 같다.
Controller에 Insert에 사용될 메서드를 적는다.
(참고로 위에서는 요청 받을 시 PostDto로 받고 entity객체로 전환하도록 적었는데 mybatis에 영향을 주는 부분은 아니다)
Controller 에서 호출한 Service 메서드를 작성한다.
Mapper 메서드를 작성한다.
INSERT, UPDATE, DELETE 같은 요청은 SQL문 실행 후 반환되는 결과가 있는게 아니므로 void 타입으로 선언한다.
파라미터는 객체타입으로 받았으므로 객체타입으로 선언한다.
Mapper Interface에서 작성한 메서드를 mapper.xml에서 작성한다.
파라미터 타입을 객체타입으로 받으므로 parameterType에 객체 위치를 적는다.
그리고 values 안에 #{객체멤버} 를 적는다.
포스트맨으로 요청을 보낸다.
요청을 보낼 때 콘솔에 위와 같이 확인할 수 있고,
쿼리를 확인하면 값이 insert 된 것을 볼 수 있다.
Controller에 update에 사용될 메서드를 적는다.
update에 사용될 데이터를 PatchDto타입으로 받고 변환한다.
Controller에서 호출된 Service 메서드를 작성한다.
파라미터는 객체타입으로 받았으므로 객체타입으로 선언한다.
Mapper Interface에서 작성한 메서드를 mapper.xml에서 작성한다.
파라미터 타입을 객체타입으로 받으므로 parameterType에 객체 위치를 적는다.
그리고 categoryName 은 기존 데이터를 변경시킬 내용이므로 set 부분에 작성하고, categoryId 는 변경대상 Id 이므로 where 부분에 작성한다.
포스트맨으로 요청을 보내면
콘솔에 위와 같이 확인할 수 있고
쿼리로 위와 같이 값이 변경된 것을 확인할 수 있다.
Controller에 delete에 사용될 메서드를 적는다.
파라미터값으로 삭제대상 Id값을 받는다.
Controller에서 호출된 Service 메서드를 작성한다.
Delete 용 메서드를 선언한다.
categoryId를 파라미터를 쓰므로 @Param을 사용한다.
Mapper Interface에 선언한 메서드를 작성한다.
Mapper Interface 메서드에서 선언한 @Param 파라미터를
#{categoryId} 로 받는다.
포스트맨으로 요청을 보내면
위와 같이 콘솔을 확인할 수 있고,
쿼리에서 데이터가 삭제된 것을 확인할 수 있다.