대표적으로 카테고리의 계층형 결과를 조회할 때 이 방법이 사용될 수 있다.
실제로 실무에서 사용 중인 테이블 구조와 소스코드를 필요한 부분만을 예제로 사용했다.
오라클처럼 계층형 쿼리가 있는 dbms라면 좋겠지만, mysql은 쿼리에서 지원되지 않는다.
별도의 함수를 만들거나 with recursive 라는 지시어를 사용하던데 mybatis로 해결이 되는 일이기 때문에 일일이 시도해보지 않았다.
샘플 데이터 계층 구조
데이터의 계층 구조는 다음과 같다. (* 코드명 ... 코드 형식으로 표기)
- 인사기준 ... L1
- 출장 ... L1_M1
- 국내 출장 ... L1_M1_S1
- 해외 출장 ... L1_M1_S2
- 퇴직 ... L1_M2
- 퇴직금 산출기준 ... L1_M2_S1
- 퇴직금 중간정산 ... L1_M2_S2
- 출장 ... L1_M1
- 복리후생 ... L2
- 어학 지원 ... L2_M1
- 경조사 지원 ... L2_M2
데이터베이스 테이블
위 데이터를 저장하고 있는 데이터베이스 테이블은 다음과 같다. (* 테이블 명: tb_category)
id | code | code_name | up_code |
1 | L1 | 인사기준 | null |
2 | L2 | 복리후생 | null |
3 | L1_M1 | 출장 | L1 |
4 | L1_M2 | 퇴직 | L1 |
5 | L2_M1 | 어학 지원 | L2 |
6 | L2_M2 | 경조사 지원 | L2 |
7 | L1_M1_S1 | 국내 출장 | L1_M1 |
8 | L1_M1_S2 | 해외 출장 | L1_M1 |
9 | L1_M2_S1 | 퇴직금 산출기준 | L1_M2 |
10 | L1_M2_S2 | 퇴직금 중간정산 | L1_M2 |
JAVA 모델 객체
위의 데이터를 아래의 모델 객체에 Set 할 것이다.
@Getter
@Setter
@ToString
Class Category {
private long id; // 고유 id
private String code; // 코드
private String codeName; // 코드 명
private String upCode; // 상위 카테고리 코드
private List<Category> children; // 하위 카테고리 목록
}
children 필드에는 하위 카테고리 목록이 Set 된다.
데이터 조회 쿼리
Mybatis의 Mapper.xml 설정을 보기 전에 mysql은 계층형 쿼리를 지원하지 않는데 어떻게 데이터를 조회하는지, 그 쿼리문을 보자.
select
l.id l_id, l.code l_code, l.code_name l_codeName, l.up_code l_upCode,
m.id m_id, m.code m_code, m.code_name m_codeName, m.up_code m_upCode,
s.id s_id, s.code s_code, s.code_name s_codeName, s.up_code s_upCode
from
tb_category l
left outer join tb_category m on (l.code = m.up_code)
left outer join tb_category s on (m.code = s.up_code)
위의 쿼리 결과는 계층형으로 나오지 않는다.
계층 구조가 예제와 같이 L > M > S 라면 하나의 row에 L,M,S 컬럼이 모두 조회된다.
그래서 총 결과 수는 각 Category 별 최하위 분류 개수 만큼 결과 row가 나온다.
위의 쿼리에서 몇몇 컬럼을 덜어내고 결과를 표시해보자면 다음과 같다.
l_code | l_codeName | m_code | m_codeName | s_code | s_codeName |
L1 | 인사기준 | L1_M1 | 출장 | L1_M1_S1 | 국내 출장 |
L1 | 인사기준 | L1_M1 | 출장 | L1_M1_S2 | 해외 출장 |
L1 | 인사기준 | L1_M2 | 퇴직금 | L1_M2_S1 | 퇴직금 산출 기준 |
L1 | 인사기준 | L1_M2 | 퇴직금 | L1_M2_S2 | 퇴직금 중간 정산 |
L2 | 복리후생 | L2_M1 | 어학지원 | (null) | (null) |
L2 | 복리후생 | L2_M2 | 경조사 지원 | (null) | (null) |
이렇게 한 줄에 한 분류를 모두 표시하는 쿼리문을 작성한 다음 Mapper.xml 을 작성할 수 있다.
Mapper.xml
<resultMap />과 <select />을 다음과 같이 작성한다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<resultMap id="categoryHierarchyMap" type="com.navercorp.app.user.vo.Category">
<id column="l_id" property="id" javaType="long"/>
<result column="l_code" property="code" javaType="string"/>
<result column="l_codeName" property="codeName" javaType="string"/>
<result column="l_upCode" property="upCode" javaType="string"/>
<collection property="children" ofType="com.navercorp.app.user.vo.Category">
<id column="m_id" property="id" javaType="long"/>
<result column="m_code" property="code" javaType="string"/>
<result column="m_codeName" property="codeName" javaType="string"/>
<result column="m_upCode" property="upCode" javaType="string"/>
<collection property="children" ofType="com.navercorp.app.user.vo.Category">
<id column="s_id" property="id" javaType="long"/>
<result column="s_code" property="code" javaType="string"/>
<result column="s_codeName" property="codeName" javaType="string"/>
<result column="s_upCode" property="upCode" javaType="string"/>
</collection>
</collection>
</resultMap>
<select id="selectCategoryHierarchy" resultMap="categoryHierarchyMap">
select
l.id l_id, l.code l_code, l.code_name l_codeName, l.up_code l_upCode,
m.id m_id, m.code m_code, m.code_name m_codeName, m.up_code m_upCode,
s.id s_id, s.code s_code, s.code_name s_codeName, s.up_code s_upCode
from
tb_category l
left outer join tb_category m on (l.code = m.up_code)
left outer join tb_category s on (m.code = s.up_code)
</select>
</mapper>
'생계유지형 개발자 > Spring Framework' 카테고리의 다른 글
[Spring5] Thymeleaf + Vue CDN 혼용하기 (0) | 2021.03.24 |
---|---|
[Spring5] Spring MVC vs WebFlux (0) | 2021.03.23 |
[Spring5] WebFlux + Thymeleaf + Kotlin (0) | 2021.02.02 |
[Spring] proprteis 파일 한글 깨짐 (0) | 2020.07.15 |
[spring] application.yml에 정의한 값이 상수이며 0으로 시작할 때 @Value 형변환 오류 (2) | 2020.01.03 |