๐ Backend

RDS :: Too many connections ์ค๋ฅ ํด๊ฒฐ (mariaDB)
๋ฌธ์ ์ํฉ ์คํ๋ง ์๋ฒ๋ฅผ ๋์ปค ์ปจํ ์ด๋๋ก ์คํํ๋๋ฐ ๊ฐ์๊ธฐ Too many connections ์๋ฌ ๋ฐ์..! DB ๋ AWS RDS ๋ก mariadb (t3.micro) ๋ฅผ ์ฌ์ฉ ์ค์ด๋ค. ์ธํ ํ์ธ ํ์ฌ ์ฐ๊ฒฐ๋์ด ์๋ thread ์์ ์ง์ ๋ wait timeout ๊ฐ, max connections ๊ฐ์ ํ์ธํด๋ณด์. ์ฐ๊ฒฐ๋ thread ์ ํ์ธ SHOW STATUS LIKE โthreads_connectedโ; ํ์ฌ wait timeout ๊ฐ ํ์ธ SHOW VARIABLES LIKE โwait_timeoutโ; ํ์ฌ max connections ๊ฐ ํ์ธ SHOW VARIABLES LIKE โmax_connectionsโ; ํ์ธํด๋ณด๋ max connections ๊ฐ์ด 30 ์ผ๋ก ๋์ด ์๋๋ฐ, ์ฐ๊ฒฐ๋ th..

RDS :: Incorrect string value: '\xEC\x9D\xB4\xEC\xA3\xBC...' for column ์ค๋ฅ ํด๊ฒฐ (mariaDB)
๋ฌธ์ ์ํฉ ์นด์นด์ค ๋ก๊ทธ์ธ ์ดํ ๋ฐ์์จ nickname ๊ฐ์ DB ์ ์ ์ฅํ๋ ค๊ณ ํ๋๋ฐ Incorrect string value ์๋ฌ๊ฐ ๋ด๋ค. ๊ฒ์ํด๋ณด๋ ํด๋ผ์ด์ธํธ์์ ๋ณด๋ธ ๋ฐ์ดํฐ๋ฅผ DB ์ ๋ฃ์ผ๋ ค ํ ๋, ๊ทธ ๋ฐ์ดํฐ๊ฐ ํ๊ธ์ด๋ฉด ์ค๋ฅ์ธ ๊ฒ์ผ๋ก ๋ฌธ์ ๋ฅผ ํ์ ํ ์ ์์๋ค ! DB ์ character set ์ utf-8 ๋ก ์ค์ ํ๋ฉด ๋ฐ๋ก ํด๊ฒฐ๋๋ ๋ฌธ์ . ํด๊ฒฐ๋ฐฉ์ RDS ์ ํ๋ผ๋ฏธํฐ ๊ทธ๋ฃน์ ์์ ํด์ค๋ค. ๋ง์ฝ RDS์ default ํ๋ผ๋ฏธํฐ ๊ทธ๋ฃน์ด ์ ์ฉ๋์ด ์๋ค๋ฉด ํ๋ผ๋ฏธํฐ ๊ทธ๋ฃน์ ์๋ก ๋ง๋ค๋ฉด ๋๋ค. ํ๋ผ๋ฏธํฐ ๊ทธ๋ฃน์์ character ๋ฅผ ๊ฒ์ํด๋ณด์. ๊ฒ์ํด์ ๋์ค๋ character_set ๋ค์ ๊ฐ์ ์ ๋ถ utf8mb4 ๋ก ๋ฐ๊ฟ์ฃผ์. utf8 ๋ก๋ง ๋ณ๊ฒฝํด๋ ๋์ง๋ง, ์ด๋ชจ์ง์ ๊ฐ์ ๊ฐ๋ค์ DB ์ ๋ฃ๊ณ ์ถ๋ค๋ฉด mb..

Spring Boot :: @FeignClient ๋ก ์ธ๋ถ REST API ๊ฐํธ ํธ์ถ
๋ค์ด๊ฐ๋ฉด์ ์นด์นด์ค ๋ฐ ์ ํ ๋ก๊ทธ์ธ์ ๊ตฌํํ๋ฉด์ ์ธ๋ถ API ์๋ฒ์ ์ ๊ทผํด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์์ผ ํ๋ ์ผ์ด ๋ง์์ก๊ณ , API ์ฃผ์๋ฅผ ์ค์ ํ์ผ์ ์ ์ฅํ ํ ์ง์ HttpURLConnection ์ ์์ฑํด์ ์ฐ๊ฒฐํ๋ ์ฝ๋๊ฐ ์ค๋ณต๋๊ฒ ๋์๋ค. ๋ ์ง์ HttpURLConnection ์ ์ฐ๊ฒฐํด ์ธ๋ถ API ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ฉด ๋ฐ์์จ JSON ์ ์ง์ ํ์ฑํด์ผ ํ๋ ๋ถํธํจ๋ ์กด์ฌํ๋ค. ์ ๋ฆฌํ์๋ฉด, ์ธ๋ถ API ๋ฅผ ๊ฐํธํ๊ฒ ํธ์ถํ๊ณ ์ถ์ด์ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ์ง์ ํ์ฑํ๋ ๊ณผ์ ์ด ๋ฒ๊ฑฐ๋ก์์ FeignClient ๋ฅผ ์ฌ์ฉํ๊ฒ ๋์๋ค. ์๋ ์ค๋ช ์์๋ ๋ง์ด ์์๋ฅผ ๋๋ Github API ๋ฅผ ์ด์ฉํด์ ์ฝ๋๋ฅผ ์์ฑํด๋ณด์๋ค. FeinClient Feign ์ Netflix ์์ ๊ฐ๋ฐํ REST Client ์ด๋ค. ๊ธฐ์กด์ Rest..

EC2 :: Ubuntu Swap ๋ฉ๋ชจ๋ฆฌ ์ค์
EC2 ํ๋ฆฌํฐ์ด ์๋ฒ๋ก ์คํ๋ง์ ๋์ฐ๊ณ , CI/CD ๋ฅผ ์ธํ ํ๊ณ ํ๋ค๋ณด๋ฉด ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ถ์กฑํ ๊ฒฝ์ฐ๊ฐ ์ข ์ข ์๋ค. ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋๋ฆฌ๋ ค๋ฉด ๊ณผ๊ธ์ ํด์ผํ๊ณ .. ๊ฐ๋จํ ์ค์ต์ด๋ ๊ฐ๋ฐ์ฉ ํ๊ฒฝ ์ธํ ์ด๋ผ๋ฉด ์ฌ์์ ์ฌ๋ฆฌ๊ธฐ๋ณด๋ค Swap ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ด์ฉํด ์ด๋ฅผ ํด๊ฒฐํ ์ ์๋ค. Swap ํ์ผ ๋๋ ํํฐ์ ํ์ธ sudo free -m Swap ์์ญ์ด 0 ์ด๋ ์ค์ ์ ํด์ฃผ์ Swap ํ์ผ ์์ฑ sudo fallocate -l 2G /swapfile ์ฉ๋์ด 2G ์ธ swapfile ์ด๋ ์ด๋ฆ์ ํ์ผ์ ์์ฑํ๋ค. ์ ํ์ผ์ ์ค์ํ์ผ๋ก ์ค์ ํ์. sudo mkswap /swapfile 600์ permission ์ ๊ถ์ฅํ๋ค๊ณ ํ๋ ๋ฐ๊ฟ์ฃผ์. sudo chmod 600 /swapfile Swap ํ์ฑํ sudo swapon /swapfil..

JUnit :: ParameterizedTest ๋ก ๊ฒฝ๊ณ๊ฐ ํ ์คํธํ๊ธฐ
๊ฒฝ๊ณ๊ฐ์์ ์ฅ์ ๊ฐ ๋ง์ด ์ผ์ด๋๋ค ํ ์คํธํ ๋๋ input ๊ฐ์ ๊ฒฝ๊ณ๊ฐ์ ๋ํด์ ํญ์ ํ ์คํธ๋ฅผ ์งํํด์ผ ํ๋ค ๊ทธ๋ฌ๊ธฐ ์ํด ParameterizedTest ๋ฅผ ์ด์ฉํ๋ฉด ์ฌ๋ฌ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ค. build.gradle ์์ junit-jupiter-params ์ถ๊ฐ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2' ์์ธํ ๋ด์ฉ์ ์๋ ๋งํฌ ์ฐธ์กฐ https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/ ์ค์ต ๋น๋ฐ๋ฒํธ ์ ๋ ฅ ๊ฐ ๊ฒ์ฆ ํ ์คํธ ์๊ตฌ์ฌํญ ๋น๋ฐ๋ฒํธ๋ ์ต์ 8์ ์ด์ 12์ ์ดํ์ฌ์ผ ํ๋ค. ๋น๋ฐ๋ฒํธ๊ฐ 8์ ๋ฏธ..

JPA :: ๋ฒํฌ์ฑ ์์ ์ฟผ๋ฆฌ
๋ฒํฌ ์ฐ์ฐ ์ฌ๋ฌ ๊ฑด์ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ์์ ํ๊ฑฐ๋ ์ญ์ ์กฐ๊ฑด์ ๋ง๋ ๊ฐ์ฒด๋ฅผ ๋ค ๊ฐ์ง๊ณ ์์ ์์ ํ ํ์ ์์ด DB ์ฟผ๋ฆฌ๋ก ํด๊ฒฐํ๋ ๊ฒ. JPA Bulk ์์ ์ฝ๋ : ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์ ๋์ด๋ณด๋ค ๋ง์ ํ์๋ค์ ๋์ด๋ฅผ +1 ์ํจ๋ค. public int bulkAgePlus(int age) { return em.createQuery( "update Member m set m.age = m.age + 1" + " where m.age >= :age") .setParameter("age", age) .executeUpdate(); } ํ ์คํธ ์ฝ๋ @Test public void bulkUpdate() { //given memberJpaRepository.save(new Member("member1", 10)); m..

JPA :: ํ์ด์ง๊ณผ ์ ๋ ฌ
๊ธฐ์กด JPA ํ์ด์ง๊ณผ ์ ๋ ฌ public List findByPage(int age, int offset, int limit) { return em.createQuery("select m from Member m where m.age = :age order by m.username desc") .setParameter("age", age) .setFirstResult(offset) .setMaxResults(limit) .getResultList(); } public long totalCount(int age) { return em.createQuery("select count(m) from Member m where m.age = :age", Long.class) .setParameter("age", a..

JPA :: Query Method ๊ธฐ๋ฅ
์คํ๋ง ๋ฐ์ดํฐ JPA ๊ฐ ์ ๊ณตํ๋ ๋ง๋ฒ๊ฐ์ ๊ธฐ๋ฅ์ด ์๋ค. ๋ฐ๋ก โ์ฟผ๋ฆฌ ๋ฉ์๋โ ๊ธฐ๋ฅ์ธ๋ฐ, ๊ฒฐ๋ก ๋ถํฐ ๋งํ๋ฉด 3๊ฐ์ง ๊ธฐ๋ฅ์ด ์๋ค. ๋ฉ์๋ ์ด๋ฆ์ผ๋ก ์ฟผ๋ฆฌ ์์ฑ ๋ฉ์๋ ์ด๋ฆ์ผ๋ก JPA NamedQuery ํธ์ถ @Query ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด์ Repository interface ์ ์ฟผ๋ฆฌ ์ง์ ์ ์ Method ์ด๋ฆ์ผ๋ก Query ์์ฑ ๋ฉ์๋ ์ด๋ฆ์ ๋ถ์ํด์ JPQL ์ฟผ๋ฆฌ ์คํ ์) ์ด๋ฆ๊ณผ ๋์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ํ์์ ์กฐํํ๋ ค๋ฉด ? // ์์ JPA Repository public List findByUsernameAndAgeGreaterThan(String username, int age) { return em.createQuery("select m from Member m where m.username = :us..