CS/Database

[MyBatis] MyBatis의 Association과 Collection

별토끼. 2021. 8. 10. 23:17
반응형

MyBatis에서 Domain 객체와 쿼리를 맵핑을 하다가 막혀서 이 부분을 공부하게 되었다. flat하게 데이터를 주는 쿼리와 다르게, 계층형태로 데이터를 전달해야하다 보면 편하게 맵핑할 방법을 찾게 된다. 이걸 Association과 Collection으로 해결할 수 있다.

세 개의 도메인으로 예를 들어보자.

Artist - Album - Song

Artist는 여러개의 앨범을 낼 수 있다. Album 안에는 여러 개의 Song이 있다. 즉, Artist와 Album은 1:N의 관계이다. Album과 Song 역시 1:N 관계이다.

만약 특정한 seq번호가 3인 앨범의 정보와 아티스트, 앨범 A에 수록된 곡을 알고 싶다면 어떻게 해야할까?

기존의 나

  1. select로 seq번호가 3인 앨범 정보를 가져온다.
  2. Artist는 seq번호로 JOIN을 이용해 가져온다.
  3. Song은 seq번호로 가져오면 되는데, 여러 개의 결과값이 있다.
  4. Dao에서 Song을 가져오는 로직을 만든다.
  5. 그럼 List로 받아서 비즈니스 로직을 작성한다.
  6. 데이터 한번 가져오는데 DB 접근은 두번 한다.
  7. 코드는 지저분하다.

뽀글 뽀글....

Association과 Collection

Association과 Collection을 이용하면 기존의 나보다 훨씬 편하게 코드를 짤 수 있다. 훨씬 편리하고, 효율적이다.

Association

Association은 has one 관계를 설정할 수 있다. 즉, Artist - Album은 1 - N 관계이다. 앨범 입장에서는 아티스트는 하나만 존재한다. 따라서, MyBatis 내 resultMap 내부에서 association을 활용해 데이터를 가져올 수 있다.

이때, join을 이용해 한번에 가져오거나 select 구문을 추가하여 가져오는 방법 중 선택할 수 있다. 아래 코드는 select 구문을 이용했다.

select를 이용한 방법

<resultMap id="albumResultMap" type="com.devop.test.core.entity.album.Album">
      ..(생략)
    <association column="artist_seq" property="artist" select="[1] : selectArtistByPrimaryKey"/>
      ..(생략)
</resultMap>

<select id="[1] : selectArtistByPrimaryKey" 
        resultMap="artistResultMap" parameterType="java.lang.Long">
  select
  seq, name, debut_date
  from
  artists
  where
  seq = #{seq, jdbcType=BIGINT}
</select>

join을 이용한 방법

<resultMap id="[1] : artistResultMap" type="com.devop.test.core.entity.artist.Artist">
  <id column="seq" property="seq" jdbcType="BIGINT"/>
  <result column="name" property="name" jdbcType="VARCHAR"/>
  <result column="debut_date" property="debutDate" jdbcType="TIMESTAMP"/>
</resultMap>

<resultMap id="albumResultMap" type="com.devop.test.core.entity.album.Album">
      ..(생략)
    <association property="artist" resultMap="artistResultMap"/>
      ..(생략)
</resultMap>

<select id="[1] : selectArtistByPrimaryKey" 
        resultMap="artistResultMap" parameterType="java.lang.Long">
  select
  seq, name, debut_date
  from
  artists
  where
  seq = #{seq, jdbcType=BIGINT}
</select>

Collection

Collection은 has many 관계를 설정할 수 있다. 즉, Album - Song은 1 - N 관계이다. 아까와는 달리, Album은 하나인데 노래는 여러 곡이 존재한다.

Association과 마찬가지로, select 구문을 추가하거나 join을 이용해 가져올 수 있다.

<resultMap id="albumResultMap" type="com.devop.test.core.entity.album.Album">
      ..(생략)
    <collection column="seq" property="songs" select="[2] : selectSongByAlbumKey"/>
      ..(생략)
</resultMap>

..생략

이렇게 하면 이 데이터들을 각 도메인에 적절하게 주입받아 전달할 수 있게 된다. !!
잘 활용하도록 하자.

참고를 위한 전체 코드

<?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" >

<mapper namespace="com.devop.test.core.repo.album.AlbumRepository">
    <!-- Result Map 선언  -->
    <resultMap id="albumResultMap" type="com.devop.test.core.entity.album.Album">
        <id column="seq" property="seq" jdbcType="BIGINT"/>
        <result column="title" property="title" jdbcType="VARCHAR"/>
        <result column="stock" property="stock" jdbcType="INTEGER" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>
        <result column="issueDate" property="issueDate" jdbcType="TIMESTAMP"/>
        <!-- association -->
        <association column="artist_seq" property="artist" select="[1] : selectArtistByPrimaryKey"/>

        <!-- collection -->
        <collection column="seq" property="songs" select="[2] : selectSongByAlbumKey"/>
    </resultMap>

    <!-- SELECT Query  -->  
    <select id="[1] : selectArtistByPrimaryKey" 
    resultMap="artistResultMap" parameterType="java.lang.Long">
        select
            seq, name, debut_date
        from
            artists
        where
            seq = #{seq, jdbcType=BIGINT}
    </select>

    <!-- SELECT Query  -->
    <select id="[2] : selectSongByAlbumKey" 
    resultMap="songResultMap" parameterType="java.lang.Long">
        select
            seq, album_seq, name, playtime
        from
            songs
        where
            album_seq = #{seq, jdbcType=BIGINT}
    </select>
</mapper>

참고
https://lyb1495.tistory.com/110

반응형