๐Ÿ๏ธ Spring

๐Ÿค” ์„œ๋ก  ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Redis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ„์‚ฐ๋ฝ์„ ๊ตฌํ˜„ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. Java์˜ Redis ํด๋ผ์ด์–ธํŠธ๋กœ๋Š” Jedis, Lettuce, Redisson ๋“ฑ์ด ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ์˜ ํŠน์ง•์ด ์„œ๋กœ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์ด์ค‘์—์„œ Jedis๋Š” ์ œ์™ธํ•˜๊ณ  Lettuce์™€ Redisson์„ ์‚ฌ์šฉํ•ด์„œ ๋ถ„์‚ฐ๋ฝ์„ ๊ตฌํ˜„ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. (Jedis์™€ Lettuce์˜ ๋น„๊ต๋Š” ๋‹ค์Œ ๊ธ€์„ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”) ๐Ÿค” Redis ํ™˜๊ฒฝ ์„ค์ • ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด redis๋ฅผ ๋‹ค์šด๋ฐ›์•„์ค๋‹ˆ๋‹ค. (๋ฐ˜๋“œ์‹œ ๋„์ปค๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.) docker pull redis ์ดํ›„ ๋ ˆ๋””์Šค๋ฅผ ์‹คํ–‰์‹œ์ผœ์ค๋‹ˆ๋‹ค. docker run --name redis -d -p 6379:6379 redis ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Redis ๊ด€๋ จ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. imple..
๐Ÿค” ์„œ๋ก  ์ด์ „ ๊ธ€์—์„œ๋Š” ๋น„๊ด€์  ๋ฝ(Pessimistic Lock)๊ณผ ๋‚™๊ด€์  ๋ฝ(Optimistic Lock)์„ ํ†ตํ•ด ๋ถ„์‚ฐ๋ฝ์„ ๊ตฌํ˜„ํ•˜์—ฌ ๋‹จ์ผ ์„œ๋ฒ„๋Š” ๋ฌผ๋ก  ๋‹ค์ค‘ ์„œ๋ฒ„์—์„œ๋„ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๋น„๊ด€์  ๋ฝ๊ณผ ๋น„์Šทํ•œ MySQL์˜ USER-LEVEL Lock(Named Lock)์„ ํ†ตํ•ด์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. (์•ž์œผ๋กœ๋Š” user-level lock์ด๋ผ๊ณ  ๋ถ€๋ฅด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.) ๐Ÿค” USER-LEVEL Lock (Named Lock) MySQL ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ user level lock์„ ์ง€์›ํ•ด์ฃผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿณ GET_LOCK(str, timeout) ์ฃผ์–ด์ง„ ์ด๋ฆ„(str)์— ๋Œ€ํ•œ Lock ํš๋“์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋Š” ์ตœ๋Œ€ 64๊ธ€์ž์ž…..
๐Ÿค” ์„œ๋ก  ์ด์ „ ๊ธ€์—์„œ ์•Œ์•„๋ณธ synchronized๋Š” ๋‹จ์ผ ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ๋งŒ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๋‹ค์ค‘ ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๋Œ€์˜ ์„œ๋ฒ„์—์„œ ๋™์ผ ์ž์›์— ์ ‘๊ทผํ•˜๋Š” ๊ฒฝ์šฐ, ๋™์‹œ์— ํ•œ ๊ฐœ์˜ ํ”„๋กœ์„ธ์Šค(ํ˜น์€ ์“ฐ๋ ˆ๋“œ)๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” Lock์„ ๋ถ„์‚ฐ ๋ฝ(Distributed Lock)์ด๋ผ ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ์ด์ œ๋ถ€ํ„ฐ ๋ถ„์‚ฐ ๋ฝ์„ ๊ตฌํ˜„ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•๋“ค์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ’ก ๋ถ„์‚ฐ ๋ฝ์— ๋Œ€ํ•ด์„œ ๋ถ„์‚ฐ ๋ฝ์— ๋Œ€ํ•ด์„œ ์ด๋ ‡๋‹ค ํ•  ์™„์ „ํ•œ ์ •์˜๋ฅผ ์ฐพ์ง€๋Š” ๋ชปํ•ด์„œ ๋‹ค์Œ ๋‘ ์ƒํ™ฉ์ด ํ˜ผ๋™๋  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. 1. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ๋Œ€์ธ ๊ฒฝ์šฐ, ์ด๋“ค๊ฐ„์˜ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” Lock 2. ์Šค์ผ€์ผ..
๐Ÿค” ์„œ๋ก  ๋‹ค์ค‘ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ํ•œ ๋ฒˆ์ฏค์€ ๋™์‹œ์„ฑ ๋ฌธ์ œ์— ์ ‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ํ•˜๋‚˜์˜ ์ž์›์— ๋Œ€ํ•ด์„œ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜์—ฌ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ์— ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ๋กœ๋Š” ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์˜ ์กฐํšŒ ์ˆ˜๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฆ๊ฐ€๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์— 100๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒฝ์šฐ ์กฐํšŒ์ˆ˜๋Š” 100์ด ๋˜์–ด์•ผ ์˜ณ๊ฒ ์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์กฐํšŒ์ˆ˜๋Š” 100๋ณด๋‹ค ์ž‘์€ ๊ฐ’์œผ๋กœ ์„ค์ •๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์กฐํšŒ์ˆ˜ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ๋Œ€์ฒด๋กœ ๋ฐ์ดํ„ฐ์˜ ์ •ํ•ฉ์„ฑ์ด ์ค‘์š”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ถ€๋ถ„์ด ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ƒํ’ˆ์˜ ์žฌ๊ณ  ์ˆ˜๋Ÿ‰๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์— ์ด๋Ÿฌํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์น˜๋ช…์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค..
(์ œ ๊ถ๊ธˆ์ฆ ํ’€ ์šฉ๋„๋กœ ์ •๋ฆฌํ•œ๊ฑฐ๋ผ ๋ง‰ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.) ๐Ÿง ManyToOne, OneToOne ์—ฐ๊ด€๊ด€๊ณ„ ์ผ๋ฐ˜์ ์œผ๋กœ merge ์‹œ merge๋˜๋Š” ํŠน์ • ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•ด์„œ๋งŒ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ cascade ์†์„ฑ์ด MERGE๋ผ๋ฉด merge ์‹œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋“ค๋„ left join์œผ๋กœ ์กฐํšŒํ•ด์˜ต๋‹ˆ๋‹ค. merge()๊ฐ€ ๋˜์–ด ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ๋„ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” fk ๊ฐ’์˜ ๋ณ€๊ฒฝ๋งŒ์ด ๋ฐ˜์˜๋˜์ง€๋งŒ, cascade ์†์„ฑ์ด merge๋ผ๋ฉด ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ์˜ ๋ณ€๊ฒฝ๋„ ํ•จ๊ป˜ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค. (DB ๊ด€์ ์—์„œ ์ƒ๊ฐํ•˜๋ฉด ํŽธํ•ฉ๋‹ˆ๋‹ค) @NoArgsConstructor @Accessors(fluent = true) @Getter @Entity public class Member { @Id @GeneratedValue(strategy = Ge..
๐Ÿง ๋ฌธ์ œ ์ƒํ™ฉ @Service @Transactional @RequiredArgsConstructor public class PostService { private final PostRepository postRepository; private final MemberRepository memberRepository; public Long create(CreatePostCommand command) { Member member = memberRepository.findById(command.memberId()) .orElseThrow(NotFoundMemberException::new); Post post = command.toPost(member); Post saved = postRepository.sa..
(์ „ ์ˆœ์ • ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ธฐ ๋•Œ๋ฌธ์— React๋Š” ๋ชปํ•ฉ๋‹ˆ๋‹ค. React ์ฝ”๋“œ๋Š” Chat GPT ์‹œ์ผœ์„œ ๊ตฌํ˜„ํ•˜์˜€๊ณ , ๋Œ€์‹  ๋ฐฑ์—”๋“œ์— ์˜จ ์ง„์‹ฌ์„ ๋‹ดํ•˜์„œ ๊ตฌํ˜„ํ•˜์˜€์œผ๋‹ˆ, ํ”„๋ก ํŠธ ์ฝ”๋“œ๋Š” ์ •๋ง ๊ทธ๋ƒฅ ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ๋งŒ ์ฐธ๊ณ ํ•ด ์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.) OAuth์˜ ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ๋Š” ์ด๋ฏธ ๋งŽ์€ ๋ธ”๋กœ๊ทธ๋“ค์—์„œ ๋‹ค๋ฃจ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ €๋Š” ์ด์— ๋Œ€ํ•ด์„œ๋Š” ๋”ฐ๋กœ ๋‹ค๋ฃจ์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” (์ ์–ด๋„ ์ œ๊ฐ€ ์‚ดํŽด๋ณด์•˜๋˜) ๋Œ€๋ถ€๋ถ„์˜ ๋ธ”๋กœ๊ทธ์—์„œ ์• ๋งคํ•˜๊ฒŒ ์„ค๋ช…๋˜์–ด์žˆ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ์˜ ์—ญํ• ๊ณผ, ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š”์ง€๋ฅผ ์ง‘์ค‘์ ์œผ๋กœ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ๊ณผ์ •์—์„œ ๋‹จ์ˆœํžˆ ๊ตฌํ˜„ํ•˜๊ณ  ๋๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ƒˆ๋กœ์šด ํƒ€์‚ฌ ํ”Œ๋žซํผ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ณผ์ •๋„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์œ ์—ฐํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ ธ๊ฐ€๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์†Œ์Šค ์ฝ”๋“œ๋Š”..
๐Ÿง ์ธ์ˆ˜ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™” ์ธ์ˆ˜ํ…Œ์ŠคํŠธ ํ˜น์€ ํ†ตํ•ฉํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ์—๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ๊ฒฉ๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์™€ ๊ด€๋ จํ•œ ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ์ธ์ˆ˜ํ…Œ์ŠคํŠธ์—์„œ ํ…Œ์ŠคํŠธ ๊ฒฉ๋ฆฌํ•˜๊ธฐ ๊ธ€์— ์ž์„ธํžˆ ๋‚˜ํƒ€๋‚˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•๋“ค ์ค‘ @Sql ์• ๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ truncate ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฃผ๋กœ ์‚ฌ์šฉํ–ˆ์—ˆ๋Š”๋ฐ์š”, ์ด ๋ฐฉ๋ฒ•์€ truncate.sql ํŒŒ์ผ์— ์ฝ”๋“œ๊ฐ€ ์˜์กด์ ์ด๊ฒŒ ๋˜๋ฉฐ, ํ…Œ์ด๋ธ”์ด ์ƒˆ๋กœ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์‚ญ์ œ๋˜๋Š” ๊ฒฝ์šฐ truncate.sql ํŒŒ์ผ๋„ ๊ณ„์†ํ•ด์„œ ์ˆ˜์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์„ ๋Š๊ผˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋˜ ์ค‘ BeforeEachCallback๋ผ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์•Œ๊ฒŒ๋˜์—ˆ๊ณ , ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ truncate.sql ํŒŒ์ผ ์—†์ด๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ดˆ๊ธฐํ™”๋ฅผ ์ž๋™ํ™” ์‹œ์ผฐ๋Š”๋ฐ์š”, ํ•ด๋‹น ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ..
๋ง ๋ž‘
'๐Ÿ๏ธ Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๊ธ€ ๋ชฉ๋ก