๐Ÿ’พ Database

[MyBatis] ๊ฐ์ฒด ์•ˆ์— ๋ฆฌ์ŠคํŠธ, 1:N ๊ด€๊ณ„ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (feat. ResultMap, Association, Collection)

์—ฐ_์šฐ๋ฆฌ 2022. 1. 20. 22:59
๋ฐ˜์‘ํ˜•

 

 

[MyBatis] ๋™์ž‘์›๋ฆฌ, ์‚ฌ์šฉ๋ฐฉ๋ฒ• ์ •๋ฆฌ

๋ชฉ์ฐจ MyBatis ๋“ฑ์žฅ๋ฐฐ๊ฒฝ [JDBC] ์‚ฌ์šฉ๋ฐฉ๋ฒ• JDBC : JAVA DataBase Connectivity ๊ธฐ์กด ์ž๋ฐ”์—์„œ๋Š” DB๋ฅผ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ JDBC API๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. JDBC๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ข…๋ฅ˜์— ์ƒ๊ด€์—†์ด JDBC๋งŒ ์•Œ๋ฉด ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ..

lotuus.tistory.com

์œ„์— ๊ธ€๋„ ๋ณด์‹œ๋ฉด ์ข‹์•„์šฉ

 


 

ํฌํŠธํด๋ฆฌ์˜ค ์‚ฝ์งˆ(..)์ค‘์ด๋ผ ๋ธ”๋กœ๊ทธ๊ฐ€ ๋œธํ•˜๋‹ค

์˜ค๋Š˜ ํ•˜๋ฃจ์ข…์ผ ์‚ฝ์งˆํ•œ ๊ฒฐ๊ณผ๋ฅผ ์จ๋ณด๊ฒ ๋‹ค

๋ชจ๋ฅด๊ฒŒ์จ์—ฌ..

 

๊ฒŒ์‹œํŒ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋‹ค.

๊ฒŒ์‹œ๊ธ€ 1๊ฐœ์— ํŒŒ์ผ์€ ์ตœ๋Œ€ 10๊ฐœ๊นŒ์ง€ ์ €์žฅ๋  ์ˆ˜ ์žˆ๋‹ค.

DB๋„ ์•„๋ž˜ ํ•„๋“œ์™€ ๋™์ผํ•˜๊ฒŒ ๊ตฌํ˜„๋˜์–ด์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ž(=postํ…Œ์ด๋ธ”๊ณผ postfileํ…Œ์ด๋ธ”)

class Post{
	Long id;
	String title;
	String content;
}

class PostFile{
	Long postId;
	String filePath;
	String fileName;
}
@Mapper
@Repository
public interface PostRepository {
	@Select("select * from post where id=#{postId}")
	Post findById(Long postId);
}


@Mapper
@Repository
public interface PostFileRepository {
	@Select("select * from postfile where postid=#{postId}")
	List<PostFile> findById(Long postId);
}

 

๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ๋ณด๊ธฐ๋ฅผ ์ผ๋‹จ ๋˜๋Š”๋Œ€๋กœ ๊ตฌํ˜„ํ•ด๋ณด์ž

์ €์žฅ๋œ post์™€ postfile์„ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ, postfile์—์„œ๋Š” ์ด๋ฆ„๋งŒ ์žˆ์–ด๋„๋˜๋‹ˆ๊นŒ ์ด๋ฆ„๋งŒ ๊ฑธ๋Ÿฌ๋‚ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์‘๋‹ตํ•ด์ค€๋‹ค

    public Map<String, Object> detail(Long postId) {
        Post post = postRepository.findById(postId);
        PostDTO.Response postRes = new PostDTO.Response(post);

        Map<String, Object> result = new HashMap<>();
        result.put("post", postRes);

        List<PostFile> postFiles = postFileRepository.findById(postId);
        List<String> postFileNames = new ArrayList<>();
        for (PostFile postFile : postFiles) {
            postFileNames.add(postFile.getFileName());
        }
        result.put("postFileNames", postFileNames);

        return result;
    }

 

์ผ๋‹จ post๊ฐ™์€ ๊ฒฝ์šฐ์—” ์—”ํ„ฐํ‹ฐ๋ฅผ ์ง์ ‘ view๋กœ ๋‚ด๋ ค์ฃผ๊ณ ์žˆ๋‹ค

ํ–ฅํ›„ ํ™•์žฅ์„ฑ์„ ๊ณ ๋ คํ•ด์„œ ์—”ํ„ฐํ‹ฐ๋ฅผ dto๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋‚ด๋ ค์ฃผ์ž

class PostDTO{
	Long id;
	String title;
	String content;
	List<String> fileNames;
}

 

 

๊ทธ๋ฆฌ๊ณ  ๊ตณ์ด DB์— 2๋ฒˆ ์ ‘๊ทผํ•ด์•ผํ•˜๋‚˜? JOIN์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?

SELECT post.id, post.title, post.content, postfile.filename 
FROM post LEFT JOIN postfile ON post.id=postfile.postid;

21๋ฒˆ ๊ฒŒ์‹œ๊ธ€ ๊ฐ™์€ ๊ฒฝ์šฐ์—” ํŒŒ์ผ์ด 6๊ฐœ๊ฐ€ ์žˆ๊ธฐ๋•Œ๋ฌธ์— 6๋ฒˆ ์ค‘๋ณตํ•ด์„œ ๋‚˜์˜จ๋‹ค

id, title, content ์ค‘๋ณต์€ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜์ง€? ๋˜ filename์„ ๋ฆฌ์ŠคํŠธ๋กœ ๊ฐ€์ ธ์˜ฌ์ˆ˜๋Š”์—†์„๊นŒ???

 

 

 

๊ฒ€์ƒ‰ํ•ด๋ณด๋‹ˆ ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜์˜จ๋‹ค

//Xml
//์‹คํ–‰ : findPostAndFileById(Long postId);

<resultMap id="postAndFileMap" type="PostDTO">
    <id property="id" column="id"></id>
    <result property="title" column="title"></result>
    <result property="content" column="content"></result>
    <collection property="fileNames" column="filename" javaType="List" ofType="String" select="findFileById"></collection>
</resultMap>

<select id="findPostAndFileById" resultMap="postAndFileMap" parameterType="Long">
	select * from post where id=#{postId}
</select>

<select id="findFileById" resultType="String" parameterType="Long">
	select filename from postfile where postid=#{postId}
</select>
//์–ด๋…ธํ…Œ์ด์…˜
//์‹คํ–‰ : findPostAndFileById(Long postId);

@Select("select * from post where id=#{postId}")
@Results(
	id="id", value = {
	@Result(property="title", column="title"),
	@Result(property="content", column="content"),
	@Result(property = "fileNames", javaType = List.class, many=@Many(select="findFileById"))
})
PostDTO findPostAndFileById(Long postId);

@Select("select filename from postfile where postid=#{postId}")
List<String> fileNames = findFileById(Long postId);

xml์˜ <id>, ์–ด๋…ธํ…Œ์ด์…˜์˜ id๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด post์ฒ˜๋Ÿผ ์ค‘๋ณต๋˜๋Š” ๊ฒฐ๊ณผ๋Š” ์ œ์™ธํ•ด์„œ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค๊ณ  ํ•œ๋‹ค

 

 

 

์—ฌ๊ธฐ์„œ ๋‹จ์ ์€ <collection>๊ณผ @Many์—์„œ select๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด N+1๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ!!

findPostAndFileById()๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ž๋™์œผ๋กœ findFileById()๊ฐ€ ์‹คํ–‰๋˜๊ณ , List ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค.

๋‹ค์‹œ๋งํ•ด,

findPostAndFileById()๋ฅผ ์‹คํ–‰ํ•˜๊ณ  (DB์— ์š”์ฒญ 1๋ฒˆ)

๋ฆฌ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค๊ธฐ์œ„ํ•ด ํŒŒ์ผ์ด ์žˆ๋Š”๋งŒํผ findFileById()๋ฅผ ์‹คํ–‰ํ•œ๋‹ค(ํŒŒ์ผ์ด 6๊ฐœ๋‹ˆ๊นŒ DB์— ์š”์ฒญ 6๋ฒˆ..)

 

 

 

๊ทธ๋Ÿฌ๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋‚˜..

Nested ResultMap์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค๊ณ ํ•œ๋‹ค

//Xml
//์‹คํ–‰ : findPostAndFileById(Long postId);

//๋‚˜๋Š” List<String> ์ด๋ผ์„œ ResultMap์— ํ•œ๋ฒˆ์— ๋ชฐ์•„์ฃผ๊ฒ ๋‹ค
<resultMap id="postAndFileMap" type="PostDTO">
    <id property="id" column="id"></id>
    <result property="title" column="title"></result>
    <result property="content" column="content"></result>
    <collection property="fileNames" column="id" select="fileMap"></collection>
</resultMap>

<resultMap id="fileMap" type="String">
    <result column="filename"></result>	//property๊ฐ€ ์—†๋Š” ์ด์œ ๋Š” List<String>์ด๋ผ ํ•„๋“œ๊ฐ€ ์—†์–ด์„œ
</resultMap>

<select id="findPostAndFileById" resultMap="postAndFileMap" parameterType="Long">
    select post.*, postfile.filename 
    from post left join postfile on post.id=postfile.postid
    where post.id=#{postId}
</select>

 

์•„์‰ฝ๊ฒŒ๋„ <collection>์— ๋Œ€์‘๋˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด @Many๋ผ์„œ.. XML๋กœ๋งŒ ์‚ฌ์šฉํ•ด์•ผ๋  ๊ฒƒ ๊ฐ™๋‹ค

 

 

 

์ž ๊ทผ๋ฐ ์—ฌ๊ธฐ์„œ ๋˜ํ•˜๋‚˜ ๋ฌธ์ œ

PostDTO๋Š” ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ resultMap์— ํ•˜๋‚˜ํ•˜๋‚˜ ํ•„๋“œ๋ช… ์ ์–ด๊ฐ€๋ฉด์„œ ๋งž์ถฐ์ฃผ๊ณ ...

class PostDTO{
	Long id;
	String title;
	String content;
	List<String> fileNames;
}

 

๋งŒ์•ฝ PostDTO๊ฐ€... ๊ฐ์ฒด๋„ ๋ฐ›๊ฒŒ๋œ๋‹ค๋ฉด?!

class PostDTO{
	Post post;
	List<String> fileNames;
}

(๋ญ”๊ฐ€ ORM์Šค๋Ÿฝ๊ฒŒ ๋ณ€ํ•ด๊ฐ€๊ณ ์žˆ๋‹ค)

 

 

<resultMap id="postMap" type="Post">
    <id property="id" column="id"></id>
    <result property="title" column="title"></result>
    <result property="content" column="content"></result>
</resultMap>


<resultMap id="fileMap" type="String">
    <result column="filename"></result>
</resultMap>


<resultMap id="postAndFileById" type="PostDTO">
    <association property="post" column="id" select="postMap"></association>
    <collection property="fileNames" column="id" select="fileMap"></collection>
    //column์€ ๋‘˜๋‹ค id์ด๋‹ค findPostAndFileById์—์„œ์˜ id๋กœ ๋งตํ•‘ํ•œ๋‹ค
</resultMap>

<select id="findPostAndFileById" resultMap="postAndFileById" parameterType="Long">
    select post.*, postfile.filename 
    from post left join postfile on post.id=postfile.postid
    where post.id=#{postId}
</select>

association์œผ๋กœ ๋ฐ›์•„์˜ค๋ฉด๋œ๋‹ค!

resultMap์œผ๋กœ ํ•„๋“œ ํ•˜๋‚˜ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š”๊ฑด ์–ด์ฉ”์ˆ˜์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค

 

association์€ has one ๊ด€๊ณ„๋กœ ๊ฐ์ฒด๋ฅผ ๋ฐ›์„ ๋•Œ,

collection์€ has many ๊ด€๊ณ„๋กœ ์ปฌ๋ ‰์…˜์„ ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉํ•˜์ž

 

 

 

 

๋ฐ˜์‘ํ˜•
  • ๋„ค์ด๋ฒ„ ๋ธ”๋Ÿฌ๊ทธ ๊ณต์œ ํ•˜๊ธฐ
  • ํŽ˜์ด์Šค๋ถ ๊ณต์œ ํ•˜๊ธฐ
  • ํŠธ์œ„ํ„ฐ ๊ณต์œ ํ•˜๊ธฐ
  • ๊ตฌ๊ธ€ ํ”Œ๋Ÿฌ์Šค ๊ณต์œ ํ•˜๊ธฐ
  • ์นด์นด์˜คํ†ก ๊ณต์œ ํ•˜๊ธฐ