본문 바로가기
Spring/Java

[Spring][MyBatis] resultMap과 collection을 활용해 1:N관계 데이터 한 번에 가져오기

by Devyne 2025. 7. 18.
반응형

 

현재 사내 프로젝트에서 게시물 API를 구현하고 있다.

게시물을 등록할 때, 여러 개의 첨부파일을 등록할 수 있도록 했다. 

 

이처럼, 그 게시물의 상세정보를 불러올 때 1:N 관계의 데이터를 어떻게 하면 효율적으로 가져올 수 있을지 고민이었다. 

 

찾아보니 이러한 1:N 관계의 데이터를 마이바티스에서 제공하는 <resultMap>과 <collection>을 활용하면
한 번의 쿼리로 1:N 관계의 데이터를 객체 형태로 가져올 수 있었다. 

 

우선 게시물과 첨부파일 테이블 구조를 알아보자. 

 


게시물 정보 테이블 (BBS_INFO) 

컬럼명 (Field) 데이터 타입 (Type) 제약 사항 설명 (Comment)
SQ int(11) PK, auto_increment 시퀀스
BBS_TYPE char(1) default ‘N’ 게시글타입 (N,F)
TITLE varchar(100) - 제목
CONTENTS text - 내용
V_ADMIN smallint(6) default 0 관리자보기 권한
V_LEADER smallint(6) default 0 팀장보기권한
V_EMP smallint(6) deafult 0 직원보기권한
REG_EMP_ID varchar(20) - 신청자ID
USE_YN char(1) deafult ‘Y’ 사용유무
REG_DT datetime default current_timestamp 등록일
UPD_DT datetime on update current_timestamp() 수정일

 

파일정보 테이블 (BBS_FILE)

컬럼명 (Field) 데이터 타입 (Type) 제약 사항 설명 (Comment)
SQ int(11) PK / auto_increment 시퀀스
BBS_SQ int(11) FK 게시물 SQ
FILE_NAME varchar(100) - 파일명
FILE_PATH varchar(100) - 파일경로

 

파일정보 테이블을 보면 외래키로 게시물정보 SQ 를 갖고 있다. 


이어서 DTO 구조를 살펴보자. 아래와 같이 구성했다. 

 

게시물 정보 DTO (BbsDTO)

@Data
@EqualsAndHashCode(callSuper=false)
@Alias("bbsDTO")
@Schema(description = "공지사항 및 자료실 DTO")
public class BbsDTO extends SearchDTO {
	
	@Schema(description = "게시글 ID(시퀀스)", example = "1")
	public int _seq;

	@Schema(description = "게시글 타입", example = "N/F(Notice/File)")
	public String bbs_type;
	
	@Schema(description = "게시글 제목")
	public String title;

	@Schema(description = "게시글 내용")
	public String contents;
	
	@Schema(description = "작성자 ID")
	public String emp_id;
	
	@Schema(description = "작성자명")
	public String emp_name;
	
	@Schema(description = "관리자 보기 권한", example = "0 or 1")
	public int view_admin;

	@Schema(description = "팀장 보기 권한", example = "0 or 1")
	public int view_leader;

	@Schema(description = "직원 보기 권한", example = "0 or 1")
	public int view_emp;
	
	@Schema(description = "첨부 파일 정보")
	public List<FileDTO> fileList;
	
	@Schema(description = "사용유무", example = "Y/N")
	public String use_yn;
	
	@Schema(description = "등록일")
	public String reg_date;
	
	@Schema(description = "수정일")
	public String upd_date;
	
}

 

파일 정보 DTO (FileDTO)

@Data
@Alias("fileDTO")
@Schema(description = "파일 DTO")
public class FileDTO {

    @Schema(description = "파일 시퀀스(ID)")
    private int file_seq;
    
    @Schema(description = "게시글 ID")
    private int bbs_seq;
    
    @Schema(description = "파일명")
    private String file_name;

    @Schema(description = "파일 경로")
    private String file_path;
    
}

 

BbsDTO를 보면서 파일정보를 List형태로 받기위해 List<FileDTO> 구성했다. 

 


 

이제 resultMap과 collection에 대해서 알아보자.

 

resultMap 

SQL 쿼리 결과를 자바 객체(DTO 등)에 어떻게 매핑할지 상세하게 정의하는 설계도 같은거다.

컬럼명과 객체 필드명이 다른 경우 또는 이와 같이 1:N 관계 데이터를 가져와야 하는 경우 사용한다. 

 

collection

<resultMap> 안에서 1:N 관계의 'N' 에 해당하는 부분을 처리하는 특별 지침

List와 같은 컬렉션 객체로 묶어주는 역할 

데이터베이스에서는 여러 줄로 조회된 결과를 자바에서는 List를 포함한 단일 객체로 깔끔하게 받을 수 있다. 

 

데이터베이스 쿼리 결과

 

실제 API 응답 결과

 


 

작성한 쿼리를 보자. 

 

<!-- 게시물 상세정보 쿼리 -->
<select id="getBbsInfoDetail" parameterType="bbsDTO" resultMap="bbsDetailResultMap">
    SELECT
        bbs.SQ AS bbs_sq,
        bbs.BBS_TYPE AS bbs_type,
        bbs.TITLE AS title,
        bbs.CONTENTS AS contents,
        bbs.REG_EMP_ID AS emp_id, 
        emp.EMP_NAME AS emp_name,
        bbs.USE_YN AS use_yn,
        bbs.REG_DT AS reg_date,
        bbs.UPD_DT AS upd_date,
        file.SQ AS file_seq,
        file.FILE_NAME AS file_name,
        file.FILE_PATH AS file_path
    FROM
        BBS_INFO bbs
    LEFT JOIN EMP_INFO emp ON bbs.REG_EMP_ID = emp.EMP_ID
    LEFT JOIN BBS_FILE file ON bbs.SQ = file.BBS_SQ
    <where>
        bbs.SQ = #{_seq}
        <if test="use_yn != null and use_yn != ''">
            AND bbs.USE_YN = #{use_yn}
        </if>
    </where>
</select>

<resultMap id="bbsDetailResultMap" type="bbsDTO">
    <id property="_seq" column="bbs_sq"/>
    <result property="bbs_type" column="bbs_type"/>
    <result property="title" column="title"/>
    <result property="contents" column="contents"/>
    <result property="emp_id" column="emp_id"/>
    <result property="emp_name" column="emp_name"/>
    <result property="use_yn" column="use_yn"/>
    <result property="reg_date" column="reg_date"/>
    <result property="upd_date" column="upd_date"/>
    
    <collection property="fileList" ofType="FileDTO">
        <id property="file_seq" column="file_seq"/>
        <result property="bbs_seq" column="bbs_sq"/>
        <result property="file_name" column="file_name"/>
        <result property="file_path" column="file_path"/>
    </collection>
</resultMap>

 

게시물 상세정보 쿼리에서 resultType이 아닌 resultMap으로 설정한다.

resultMap에서 매핑 규칙을 작성하는데, 'N'에 해당되는 파일 정보는 collection으로 구성한다. 

 

이렇게 resultMap과 collection을 활용해 1:N 관계의 데이터를 한 번의 쿼리로 깔끔하게 처리할 수 있다. 

반응형