JDBC를 사용해서 DB 테이블 = Java 객체 라고 생각해서 DTO를 짰을 때는 게시판에 필요한 데이터를 사용하기 위해서 아래 코드와 같이 객체를 생성했다. 각각의 컬럼을 필드라고 생각하고 컬럼 자료형에 맞는 자료형을 사용해서 필드를 생성했다.
package com.mybatis.model.vo;
import java.sql.Date;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Board {
private int boardNo;
private String boardTitle;
private String boardWriter;
private String boardContent;
private String boardOriginalFilename;
private String boardRenamedFilename;
private Date boardDate;
private int boardReadcount;
}
이 때 하나의 게시글에 작성자에 대한 정보나 게시글에 달리 댓글을 함께 출력해주려면 Member라는 객체에 사용자 정보를 담기 위해서 select문을 한 번 실행하고, 댓글들을 담기 위해서 BoardComment 객체에 담을 정보를 위해 select문을 한 번 더 실행하게 된다.
하지만 이 때 MyBatis의 <resultMap>
을 활용하면 select문 하나로 하나의 객체에 연관된 테이블의 정보까지 담아올 수 있다.
우선 Board 객체 하나를 불러왔을 때 작성자의 아이디나 닉네임에 대한 정보를 담은 Member 객체가 boardWriter에 필요하고 각 게시글에는 게시글 댓글인 BoardComment 객체를 여러 개 갖게 되니 List로 BoardComment 객체를 다수로 가질 수 있다.
그래서 Board 객체를 수정해보면 아래와 같다.
package com.mybatis.model.vo;
import java.sql.Date;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Board {
private int boardNo;
private String boardTitle;
private String boardContent;
private String boardOriginalFilename;
private String boardRenamedFilename;
private Date boardDate;
private int boardReadcount;
private List<BoardComment> comments;
private Member member; //boardWriter
}
이렇게 수정하면 하나의 Board 객체를 가져왔을 때 게시글을 작성한 사용자에 대한 정보들과 댓글 전체를 전부 가져올 수 있게 된다.
그럼 이렇게 작성했을 때 DB에서 값을 가져올 때는 어떻게 매핑해야 하는지 그 해결점을 resultMap
의 association
태그와 collection
태그가 해결해줄 수 있다.
<association>
멤버 변수(필드)로 다른 단일 객체를 가져올 때 사용한다. mapper.xml
에서 매핑 시 <association>
태그에 작성한 객체의 변수명을 property
속성 값으로 대입하고 column
대신 사용할 객체를 매핑한 resultMap
을 작성해준다.
그럼 해당 객체를 매핑하기 위해서 작성한 resultMap
을 실행해서 객체를 반환한다.
<collection>
다수의 객체를 멤버 변수(필드)로 가져올 때 사용한다. <collection>
태그 내에 property 속성 값으로 매핑할 변수명을 작성해주고 마찬가지로 해당 객체를 매핑한 resultMap
을 작성해준다.
<!-- Board 객체 매핑 -->
<resultMap id="boardMap" type="com.web.board.dto.Board">
<id property="boardNo" column="board_no"/>
<result property="boardTitle" column="board_title"/>
<result property="boardContent" column="board_content"/>
<result property="boardOriginalFilename" column="board_original_filename"/>
<result property="boardRenamedFilename" column="board_renamed_filename"/>
<result property="boardDate" column="board_date"/>
<result property="boardReadcount" column="board_readcount"/>
<!-- memberMap 실행해서 가져옴 -->
<association property="member" resultMap="memberMap"/>
<!-- commentMap 실행해서 가져옴 -->
<collection property="comments" resultMap="commentMap"/>
</resultMap>
<!-- Member 객체 매핑 -->
<resultMap id="memberMap" type="com.web.member.model.dto.Member">
<id property="userId" column="userid"/>
<result property="password" column="password"/>
<result property="userName" column="user_name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="email" column="email"/>
<result property="phone" column="phone"/>
<result property="address" column="address"/>
<result property="enrolldate" column="enrolldate"/>
</resultMap>
<!-- BoardComment 객체 매핑 -->
<resultMap id="commentMap" type="com.web.board.dto.BoardComment">
<id property="boardCommentNo" column="board_comment_no"/>
<result property="boardCommentLevel" column="board_comment_level"/>
<result property="boardCommentWriter" column="board_comment_writer"/>
<result property="boardCommentContent" column="board_comment_content"/>
<result property="boardRef" column="board_ref"/>
<result property="boardCommentRef" column="board_comment_ref"/>
<result property="boardCommentDate" column="board_comment_date"/>
<association property="board" resultMap="boardMap"/>
</resultMap>
객체 내에 객체를 매핑하는 경우 하나의 select문이 실행됐을 때 가져올 데이터를 전부 조회해야 한다. 이때 연관된 FK를 사용해서 JOIN문으로 연관된 데이터를 한 번에 불러온다.
//DAO에서 selectOne 메소드로 Board 객체 하나를 반환한다.
@Override
public Board selectBoard(SqlSession session, int no) {
return session.selectOne("member.selectBoard",no);
}
<select id="selectBoard" resultMap="boardMap" parameterType="_int">
SELECT *
FROM BOARD
LEFT JOIN BOARD_COMMENT ON BOARD_NO=BOARD_REF
JOIN MEMBER ON BOARD_WRITER=USERID
WHERE BOARD_NO=#{no}
</select>