๐Ÿ“Œโ€œ๋™์  SQL๋กœ ๊ฐ•์˜ ๊ฒ€์ƒ‰์„ ์œ ์—ฐํ•˜๊ฒŒ โ€“ LectureSqlProvider ๊ตฌํ˜„๊ธฐโ€

๐Ÿ“… 2025-07-02 โœ๏ธ ๋ฐ•์ฐฌํฌ

๐Ÿ”ง ์™œ ์ด ๊ธฐ๋Šฅ์„ ์‹œ์ž‘ํ–ˆ๋Š”๊ฐ€?

๊ฐ•์˜ ๊ฒ€์ƒ‰ ํ™”๋ฉด์„ ๋งŒ๋“ค๋‹ค ๋ณด๋‹ˆ ์ด๋Ÿฐ ์š”๊ตฌ๊ฐ€ ์Ÿ์•„์กŒ๋‹ค:

์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํ•œ ์ •์  SQL๋กœ ์‹œ์ž‘ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์กฐ๊ฑด์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์ฟผ๋ฆฌ๋Š” ๋ฌด๋„ˆ์กŒ๊ณ ,

if-else์˜ ๋Šช๊ณผ ๋ณต๋ถ™ SQL ์ง€์˜ฅ์ด ์‹œ์ž‘๋๋‹ค.

๊ทธ๋ž˜์„œ ๊ฒฐ๋‹จํ–ˆ๋‹ค.

๋™์  SQL + MyBatis SQL Provider ํŒจํ„ด์œผ๋กœ ์ „ํ™˜ํ•ด์„œ,

๊ฐ€๋…์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋™์‹œ์— ์žก๊ธฐ๋กœ.


๐Ÿงฑ ์„ค๊ณ„ ๊ตฌ์กฐ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

๊ณ„์ธต ์š”์†Œ ์„ค๋ช…
DTO LectureSearchCondition ๊ฒ€์ƒ‰ ์กฐ๊ฑด(์นดํ…Œ๊ณ ๋ฆฌ, ํ‚ค์›Œ๋“œ, ์ •๋ ฌ, ํŽ˜์ด์ง• ๋“ฑ) ์ „๋‹ฌ ๊ฐ์ฒด
Provider LectureSqlProvider SELECT, COUNT ์ฟผ๋ฆฌ ๋™์  ์ƒ์„ฑ ๋‹ด๋‹น
Mapper LectureMapper.xml ๋™์  ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด ๋ฐ”์ธ๋”ฉ
Service LectureService ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง (์กฐ๊ฑด ๋ถ„๊ธฐ, ์‘๋‹ต ๋ณ€ํ™˜ ๋“ฑ)

๐Ÿ“Œ ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ ์„ค๊ณ„

โœ… findLectures(LectureSearchCondition cond)

(ํ‰์  * 0.9) + (๋ฆฌ๋ทฐ ์ˆ˜ * 0.1) AS popularityScore
FROM lectures l
LEFT OUTER JOIN user_interactions ui
  ON l.lecture_id = ui.target_id
  AND ui.target_type = 'LECTURE'
  AND ui.interaction_kind = 'FEEDBACK'
if (cond.getKeyword() != null) {
  WHERE("title LIKE ... OR description LIKE ...");
}
if ("popular".equals(cond.getSort())) {
  ORDER_BY("popularityScore DESC");
} else {
  ORDER_BY("l.created_at DESC");
}

๐Ÿ“Œ ์‹ค์‹œ๊ฐ„ ์ธ๊ธฐ์ˆœ์„ ๋งŒ๋“ค์–ด๋‚ด๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ โ€œ์ •๋ ฌ ๊ฐ€๋Šฅ ์ง€ํ‘œโ€๋กœ ๊ฐ€๊ณตํ•ด์„œ ๋„ฃ๋Š” ๊ฒŒ ํ•ต์‹ฌ์ด์—ˆ๋‹ค.

์ด๋Ÿฐ ์ •๋ ฌ ์ง€ํ‘œ๋Š” UX์™€ ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ถ”์ฒœ์˜ ์ ˆ์ถฉ์ง€์ ์ด ๋œ๋‹ค.


โœ… countLectures(LectureSearchCondition cond)

SELECT COUNT(DISTINCT l.lecture_id)

๐Ÿงช ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค ์š”์•ฝ

์กฐ๊ฑด ์˜ˆ์‹œ ๊ธฐ๋Œ€ SQL ๋™์ž‘
์กฐ๊ฑด ์—†์Œ ์ „์ฒด ๊ฐ•์˜ ์ตœ์‹ ์ˆœ ์กฐํšŒ
keyword = โ€œJavaโ€ WHERE title LIKE โ€˜%Java%โ€™ OR description โ€ฆ
category = โ€œ์›นโ€ WHERE l.category = โ€˜์›นโ€™
sort = โ€œpopularโ€ ORDER BY popularityScore DESC
size = 20, offset = 10 LIMIT 10, 20

โœ… ๋ชจ๋“  ์ฟผ๋ฆฌ๋Š” ์ฝ˜์†” ๋กœ๊ทธ๋กœ ์ง์ ‘ ์ถœ๋ ฅํ•˜์—ฌ ์ฟผ๋ฆฌ ์ •ํ™•์„ฑ ๊ฒ€์ฆ ์™„๋ฃŒ


๐Ÿšง ๊ตฌํ˜„ ์ค‘ ๊ฒช์€ ๋ฌธ์ œ

โŒ ๋ฌธ์ œ: ์ •๋ ฌ ์กฐ๊ฑด์ด ์ž๊พธ ๋ˆ„๋ฝ๋จ


๐Ÿ“ˆ ์‹ค๋ฌดํ˜• ์ตœ์ ํ™” ์ „๋žต

ํ•ญ๋ชฉ ์ „๋žต ์ด์œ 
SQL ๊ฐ์ฒด ๊ตฌ์„ฑ org.apache.ibatis.jdbc.SQL ๊ฐ€๋…์„ฑ + ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ™•๋ณด
์ •๋ ฌ ์ ์ˆ˜ ๊ณ„์‚ฐ ํ‰์  + ๋ฆฌ๋ทฐ์ˆ˜ ์ถ”์ฒœ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ฐ„์†Œํ™” ๋ฐ ์‹ค์‹œ๊ฐ„ UX ๋ณด์žฅ
ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ title + description ๋™์‹œ LIKE ๊ฒ€์ƒ‰ ๋งŒ์กฑ๋„ ํ–ฅ์ƒ
ํŽ˜์ด์ง• ๋ฐฉ์‹ LIMIT #{offset}, #{size} ๋ฐ์ดํ„ฐ ์–‘์ด ๋งŽ์•„๋„ ์„ฑ๋Šฅ ์œ ์ง€
LEFT OUTER JOIN ๋ฆฌ๋ทฐ ์—†๋Š” ๊ฐ•์˜ ํฌํ•จ ๊ฐ•์˜ ๋‹ค์–‘์„ฑ ํ™•๋ณด

๐Ÿ”ญ ์•ž์œผ๋กœ์˜ ํ™•์žฅ ๊ณ„ํš

๊ธฐ๋Šฅ ์„ค๋ช…
๐Ÿ“Š ์ •๋ ฌ ๊ธฐ์ค€ ์ถ”๊ฐ€ ๋ฆฌ๋ทฐ๋งŽ์€์ˆœ, ๊ฐ€๊ฒฉ๋‚ฎ์€์ˆœ, ๋ฌด๋ฃŒ๋งŒ ๋ณด๊ธฐ ๋“ฑ
๐Ÿ”„ ์ธ๊ธฐ ์ ์ˆ˜ ๊ฐœ์„  ์กฐํšŒ์ˆ˜, ์ฐœ ์ˆ˜ ๋“ฑ ํฌํ•จํ•œ ๋‹ค์ค‘ ๊ฐ€์ค‘์น˜ ๋ชจ๋ธ
๐ŸŒ ๋‹ค๊ตญ์–ด ์ง€์› title_kr, title_en ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ
๐Ÿš€ ElasticSearch ์—ฐ๋™ ๋Œ€์šฉ๋Ÿ‰ ์กฐ๊ฑด ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ ํ–ฅ์ƒ
โœ… ๋‹จ์œ„ ํ…Œ์ŠคํŠธ Provider ํ•จ์ˆ˜๋ณ„ assertSQLEquals ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ์˜ˆ์ •

โœ๏ธ ํšŒ๊ณ 

์ด๋ฒˆ LectureSqlProvider ์ž‘์—…์€ ๋‹จ์ˆœํ•œ SQL ๋ฆฌํŒฉํ† ๋ง์ด ์•„๋‹ˆ์—ˆ๋‹ค.

๊ทธ ์•ˆ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตํ›ˆ์ด ์žˆ์—ˆ๋‹ค:

๐Ÿ’ก โ€œ์กฐ๊ฑด์ด ๋Š˜์–ด๋‚˜๋Š” ์‹œ์Šคํ…œ์ผ์ˆ˜๋ก, ์ฟผ๋ฆฌ๋Š” ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.โ€

MyBatis์˜ SQL() ๊ฐ์ฒด๋Š” ๋‹จ์ˆœํ•œ ๋ฌธ๋ฒ•์ด ์•„๋‹ˆ๋ผ,

๋„๋ฉ”์ธ ๋กœ์ง์„ SQL ์ˆ˜์ค€์—์„œ ๋ถ„๋ฆฌํ•˜๊ณ  ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•๋ก ์ด์—ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฌด์—‡๋ณด๋‹ค,

๋ฐฑ์—”๋“œ ์„ค๊ณ„๊ฐ€ ์ข‹์•„์•ผ ํ”„๋ก ํŠธ๊ฐ€ ๋‹จ์ˆœํ•ด์ง„๋‹ค.

์กฐ๊ฑด๋งŒ ๋„˜๊ธฐ๋ฉด ๊ทธ์— ๋งž๋Š” ๊ฐ•์˜ ๋ชฉ๋ก์„ ์ •๊ตํ•˜๊ฒŒ ์ฟผ๋ฆฌํ•ด์ฃผ๋Š” ์ด ๊ตฌ์กฐ๋Š”

์‹ค๋ฌด์—์„œ API ์„ค๊ณ„์˜ ํ•ต์‹ฌ์ด ๋ฌด์—‡์ธ์ง€ ๋‹ค์‹œ ํ•œ๋ฒˆ ๊นจ๋‹ซ๊ฒŒ ํ–ˆ๋‹ค.

โœ… ํ•œ ๋ฌธ์žฅ ์š”์•ฝ

โ€œMyBatis SQL Provider ํŒจํ„ด์œผ๋กœ ์กฐ๊ฑด ๊ธฐ๋ฐ˜ ๊ฐ•์˜ ๊ฒ€์ƒ‰์„ ์ •๊ตํ•˜๊ฒŒ ๊ตฌ์„ฑํ•˜์—ฌ, ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ UX ์ค‘์‹ฌ์˜ ์‹ค์‹œ๊ฐ„ ์ถ”์ฒœ ๊ตฌ์กฐ๋ฅผ ์™„์„ฑํ–ˆ๋‹ค.โ€