๊ณต๊ณต๋ฐ์ดํฐ๋ฅผ ํ์ฉํ ์์น ๊ธฐ๋ฐ ์ง์ญ ์์์ ์กฐํ ๋ฐ ์ถ์ฒ ์๋น์ค ์๋ก๋ฆฌ๋ณธ(Yellow Ribbon)
์๋ก๋ฆฌ๋ณธ์์ ์์์ ์ ๋ณด๋ฅผ ์กฐํํ๊ณ , ๋ฆฌ๋ทฐ๋ฅผ ๋จ๊ฒจ๋ณด์ธ์!
์ ์ ๋ค์๊ฒ ์ธ๊ธฐ ๋ง์ ์์์ ์ด ๊ถ๊ธํ์๋์? ์ธ๊ธฐ ๋ง์ง ๋ฐ ์ธ๊ธฐ ๊ธ์์น ๋ง์ง๋ ์ฐพ์๋ณผ ์ ์์ต๋๋ค.
๋ฟ๋ง ์๋๋ผ, ์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ๋ง์ง ์กฐํ ๋ฐ ์ถ์ฒ ์๋น์ค๊น์ง!
2024.10.18 ~ ์๋น์ค ์ด์์ค
(V2) 2024.10.01 - 2024.10.18
(V1) 2024.08.31 - 2024.09.03
์ด๋ฆ | Github | ๋ด๋น |
---|---|---|
๊น์์ฃผ | K-0joo | ํ์ API ์ ๋ฐ |
์ ์๊ฒฝ | jeongeungyeong | ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ์ ๋ฐ |
์ด์ง์ | jw427 | ์๊ตฐ๊ตฌ ๋ชฉ๋ก, ๋ง์ง ์์ธ ์ ๋ณด, ๋ง์ง ํ๊ฐ ์์ฑ, ์ธ๊ธฐ ๋ง์ง ์กฐํ API |
์ ์งํฌ | rhaehf | ์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ๋ง์ง ์กฐํ, ์ถ์ฒ API |
- ๐ ERD ๋ฐ ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ
- ๐ฅ๏ธ ์๋น์ค ์ํคํ ์ฒ ๋ฐ ๋ฐฐํฌ
- ๐ ๊ตฌํ ๋ด์ฉ
- ๐ API ๋ช ์ธ
- ๐ค ๊ณ ๋ฏผ ํ์
- ๐ ํธ๋ฌ๋ธ ์ํ
๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ
src
โโโโmain
โ โโโโgenerated
โ โ โโโโwanted
โ โ โโโโribbon
โ โ โโโโdatapipe
โ โ โ โโโโdomain
โ โ โ QGenrestrt.java
โ โ โ
โ โ โโโโstore
โ โ โ โโโโdomain
โ โ โ QCity.java
โ โ โ QReview.java
โ โ โ QStore.java
โ โ โ
โ โ โโโโuser
โ โ โโโโdomain
โ โ QRefreshToken.java
โ โ QUser.java
โ โ
โ โโโโjava
โ โ โโโโwanted
โ โ โโโโribbon
โ โ โ RibbonApplication.java
โ โ โ
โ โ โโโโdatapipe
โ โ โ โโโโcomponent
โ โ โ โ DataFetchTasklet.java
โ โ โ โ DataPipeJobScheduler.java
โ โ โ โ DataPipeTasklet.java
โ โ โ โ JobCompletionNotificationListener.java
โ โ โ โ
โ โ โ โโโโconfig
โ โ โ โ AppConfig.java
โ โ โ โ BatchConfig.java
โ โ โ โ DataPipeJobConfig.java
โ โ โ โ OpenApiJobConfig.java
โ โ โ โ
โ โ โ โโโโcontroller
โ โ โ โ OpenApiController.java
โ โ โ โ
โ โ โ โโโโdomain
โ โ โ โ Genrestrt.java
โ โ โ โ
โ โ โ โโโโdto
โ โ โ โ GenrestrtApiResponse.java
โ โ โ โ GyeongGiList.java
โ โ โ โ RawData.java
โ โ โ โ
โ โ โ โโโโmapper
โ โ โ โ RawDataRowMapper.java
โ โ โ โ StoreDataRowMapper.java
โ โ โ โ
โ โ โ โโโโrepository
โ โ โ โ GenrestrtRepository.java
โ โ โ โ
โ โ โ โโโโservice
โ โ โ DataProcessor.java
โ โ โ GenrestrtService.java
โ โ โ RawDataSaveService.java
โ โ โ RawDataService.java
โ โ โ
โ โ โโโโexception
โ โ โ โ BadRequestException.java
โ โ โ โ BaseException.java
โ โ โ โ ConflictException.java
โ โ โ โ ErrorCode.java
โ โ โ โ ErrorResponse.java
โ โ โ โ ForbiddenException.java
โ โ โ โ GenrestrtException.java
โ โ โ โ InternalServerException.java
โ โ โ โ NotFoundException.java
โ โ โ โ
โ โ โ โโโโhandler
โ โ โ GlobalExceptionHandler.java
โ โ โ
โ โ โโโโglobal
โ โ โ โโโโconfig
โ โ โ โ QueryDslConfig.java
โ โ โ โ RedisConfig.java
โ โ โ โ SwaggerConfig.java
โ โ โ โ
โ โ โ โโโโresponse
โ โ โ ResponseCode.java
โ โ โ ResponseDto.java
โ โ โ
โ โ โโโโstore
โ โ โ โโโโcontroller
โ โ โ โ CityController.java
โ โ โ โ ReviewController.java
โ โ โ โ StoreController.java
โ โ โ โ
โ โ โ โโโโdomain
โ โ โ โ Category.java
โ โ โ โ City.java
โ โ โ โ Review.java
โ โ โ โ Store.java
โ โ โ โ
โ โ โ โโโโdto
โ โ โ โ CityResponseDto.java
โ โ โ โ CreateReviewRequestDto.java
โ โ โ โ CreateReviewResponseDto.java
โ โ โ โ PopularStoreListResponseDto.java
โ โ โ โ ReviewListResponseDto.java
โ โ โ โ RisingPopularStoreListResponseDto.java
โ โ โ โ RisingStoreResponseDto.java
โ โ โ โ StoreDetailResponseDto.java
โ โ โ โ StoreListResponseDto.java
โ โ โ โ StoreResponseDto.java
โ โ โ โ
โ โ โ โโโโrepository
โ โ โ โ CityRepository.java
โ โ โ โ ReviewRepository.java
โ โ โ โ StoreRepository.java
โ โ โ โ StoreRepositoryCustom.java
โ โ โ โ StoreRepositoryImpl.java
โ โ โ โ
โ โ โ โโโโservice
โ โ โ CityService.java
โ โ โ ReviewService.java
โ โ โ StoreService.java
โ โ โ
โ โ โโโโuser
โ โ โโโโconfig
โ โ โ โ TokenAuthenticationFilter.java
โ โ โ โ TokenProvider.java
โ โ โ โ WebSecurityConfig.java
โ โ โ โ
โ โ โ โโโโjwt
โ โ โ JwtProperties.java
โ โ โ
โ โ โโโโcontroller
โ โ โ TokenApiController.java
โ โ โ UserApiController.java
โ โ โ UserOauthController.java
โ โ โ
โ โ โโโโdomain
โ โ โ RefreshToken.java
โ โ โ SocialType.java
โ โ โ User.java
โ โ โ
โ โ โโโโdto
โ โ โ CreateAccessTokenResponse.java
โ โ โ CreateRefreshTokenRequest.java
โ โ โ LoginRequest.java
โ โ โ LoginResponse.java
โ โ โ ProfileRequest.java
โ โ โ ProfileResponse.java
โ โ โ SignUpRequest.java
โ โ โ SignUpResponse.java
โ โ โ UpdateProfileRequest.java
โ โ โ UpdateProfileResponse.java
โ โ โ
โ โ โโโโrepository
โ โ โ RefreshTokenRepository.java
โ โ โ UserRepository.java
โ โ โ
โ โ โโโโservice
โ โ CustomUserDetail.java
โ โ KakaoOAuth2UserService.java
โ โ RefreshTokenService.java
โ โ TokenService.java
โ โ UserDetailService.java
โ โ UserOauthService.java
โ โ UserService.java
โ โ
โ โโโโresources
โ โ application-secret.yml
โ โ application.yml
โ โ
โ โโโโstatic
โ โโโโtemplates
โโโโtest
โโโโjava
โโโโwanted
โโโโribbon
โ RibbonApplicationTests.java
โ
โโโโuser
โโโโconfig
โโโโjwt
JwtFactory.java
- ์ผ๋ฐ ๋ก๊ทธ์ธ/ํ์๊ฐ์ ๊ธฐ๋ฅ
- ์นด์นด์ค ๋ก๊ทธ์ธ/ํ์๊ฐ์ ๊ธฐ๋ฅ
- Access ๋ฐ Refresh Token ์์ฑ
- ๊ฒฝ๋ ๋ฐ ์๋, ์ ์ฌ ์ถ์ฒ ํ๋กํ(์ ๋ณด ์ ๋ฐ์ดํธ/์กฐํ) ๊ธฐ๋ฅ
- ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ์๋ํ ์์คํ ์ ํตํด ์ฒ๋ฆฌ
- ๊ฒฝ๊ธฐ๋ ๊ณต๊ณต๋ฐ์ดํฐ ์์ง ๋ฐ ์๋ณธ ๋ฐ์ดํฐ ์ ์ฅ
- ์๋ณธ ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ
- ์ด์ํ
์ด๋ธ๋ก ๊ฐ๊ณต ๋ฐ์ดํฐ ์ ์ฅ
- ์ ๊ท ๋ฐ์ดํฐ๋ JDBC BATCH ๋์
- ๊ธฐ์กด ๋ฐ์ดํฐ๋ JPA UPDATE ๋์
- ์ ๋ณด์ ์ต์ ํ๋ฅผ ์ํด ์ค์ผ์ค๋ฌ ๋์
- ๊ณต๊ณต๋ฐ์ดํฐ ์์ง JOB: ๋งค์ฃผ ์์์ผ ์๋ฒฝ 3์
- ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ ๋ฐ ์ด์ JOB: ๋งค์ฃผ ์์์ผ ์๋ฒฝ 5์
- ์๊ตฐ๊ตฌ ๋ชจ๋ ๋ชฉ๋ก ์กฐํ
- ํ์์ ๋ง์ง ๋ชฉ๋ก ์กฐํ ๊ฐ๋ฅ
- ๋ง์ง ์์ธ ์ ๋ณด ์กฐํ ์ ๋ง์ง์ ๋ชจ๋ ํ๋์ ํด๋น ๋ง์ง์ ํ๊ฐ ๋ชฉ๋ก ์กฐํ
- ํ๊ฐ ๋ชฉ๋ก ์กฐํ ์ ์์ฑํ ํ์์ ๊ณ์ ๋ช , ํ๊ฐ ์ ์, ํ๊ฐ ๋ด์ฉ ์ถ๋ ฅ
- ๋ก๊ทธ์ธํ ํ์๋ง ํ๊ฐ ์์ฑ ๊ฐ๋ฅ
- ํ๊ฐ ์ ์์ ๋ด์ฉ ์ ๋ ฅ
- ํ๊ฐ ์์ฑ์ ํด๋น ๋ง์ง์ ํ์ ๋ฐ ๋ฆฌ๋ทฐ ๊ฐ์ ์ ๋ฐ์ดํธ
- ํ์์ ์ธ๊ธฐ ๋ง์ง ๋ฐ ์ธ๊ธฐ ๊ธ์์น ๋ง์ง ๋ชฉ๋ก ์กฐํ ๊ฐ๋ฅ
- ์ธ๊ธฐ ๋ง์ง์ ๊ธฐ์ค์ ๋ฆฌ๋ทฐ ๊ฐ์์ ํ์
- ์ ์ฒด ์ธ๊ธฐ ๋ง์ง ์ธ์ ์นดํ ๊ณ ๋ฆฌ๋ณ, ์ง์ญ๋ณ ์ธ๊ธฐ ๋ง์ง ์กฐํ ๊ฐ๋ฅ
- ์ธ๊ธฐ ๊ธ์์น ๋ง์ง ๊ธฐ์ค์ ์ ๋ ์์ฑ๋ ๋ฆฌ๋ทฐ ๊ฐ์
- ์ธ๊ธฐ ๋ง์ง๊ณผ ์ธ๊ธฐ ๊ธ์์น ๋ง์ง์ ์์ฃผ ์กฐํ๋๊ณ ๊ฐ์ด ์์ฃผ ๋ณ๊ฒฝ๋์ง ์๋ ๋ฐ์ดํฐ์ด๊ธฐ ๋๋ฌธ์ ์กฐํ ์ฑ๋ฅ ํฅ์์ ์ํด redis cache๋ฅผ ์ ์ฉ
- ์ ๋ณด์ ์ต์ ํ๋ฅผ ์ํด ์บ์ ๋ง๋ฃ๊ธฐ๊ฐ์ ๋ค์๋ ์์ ๊น์ง๋ก ์ค์
- ๊ฒฝ๋(lon)์ ์๋(lat)๋ก ์ค์ ๋ ์ฌ์ฉ์์ ์์น๋ฅผ ๊ธฐ์ค์ผ๋ก, ์ฃผ์ด์ง ๋ฒ์(range) ๋ด์์ ๊ฒ์ํ๊ณ , ์ ๋ ฌํ์ฌ ๋ง์ง์ ๊ฐ์์ ๋ชจ๋ ํ๋๋ฅผ ์๋ต
- ์ ๋ ฌ ๊ธฐ์ค
- ๊ฑฐ๋ฆฌ์: ์ฌ์ฉ์ ์์น์ ๋ง์ง ์ฌ์ด์ ๊ฑฐ๋ฆฌ๊ฐ ์งง์ ์์๋ก ์ ๋ ฌ (๊ธฐ๋ณธ ์ ๋ ฌ ๊ฐ)
- ํ์ ์: ๋ง์ง์ ํ์ ์ด ๋์ ์์๋ก ์ ๋ ฌ
- ์ฃผ์ด์ง ๋ฒ์ ๋ด์์ ๋ง์ง์ ๊ฒ์ํ๊ธฐ ์ํด ๊ณต๊ฐ ๋ฐ์ดํฐ ํ์
Point
์ ๊ณต๊ฐ ํจ์๋ฅผ ํ์ฉ
- ์ฌ์ฉ์ ์์น์์ 1km ๋ฐ๊ฒฝ ๋ด์ ๋ง์ง์ ๊ฒ์ํ๊ณ , ํ์ ๊ณผ ๋ฆฌ๋ทฐ ๊ฐ์๋ก ๊ณ์ฐํ ์์ ๊ธฐ์ค์ ๋์ผ๋ฉด ์ถ์ฒ
- ํ์ ๊ณผ ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ ํ์ฉํ ๊ณ์ฐ์์ ์ ์ฉํด ์ถ์ฒ ๋ง์ง์ ํํฐ๋ง
- ๊ณ์ฐ์:
ํ์ * 0.7 + (๋ฆฌ๋ทฐ ๊ฐ์ / 3000) * 0.3
- ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ 3,000๊ฐ๋ฅผ ์ด๊ณผํ ๊ฒฝ์ฐ,
(๋ฆฌ๋ทฐ ๊ฐ์ / 3000)
๋ 1๋ก ์ฒ๋ฆฌ - ๊ณ์ฐ์ ๊ฒฐ๊ณผ๊ฐ 3.0 ์ด์์ธ ๊ฒฝ์ฐ์๋ง ์ถ์ฒ
- ๊ณ์ฐ์:
๋๋ถ๋ฅ | ๊ธฐ๋ฅ | Method | URL | ๋ด๋น์ |
---|---|---|---|---|
์ ์ |
์ฌ์ฉ์ ํ๋กํ ์ ๋ฐ์ดํธ |
PUT |
/api/users/settings/{userId} |
๊น์์ฃผ |
์ ์ | ํ ํฐ ์์ฑ | POST |
/api/users/token |
๊น์์ฃผ |
์ ์ | ์ฌ์ฉ์ ํ์๊ฐ์ | POST |
/api/users/signup |
๊น์์ฃผ |
์ ์ | ์ฌ์ฉ์ ๋ก๊ทธ์ธ | POST |
/api/users/login |
๊น์์ฃผ |
์ ์ | ์ฌ์ฉ์ ํ๋กํ ํ์ธ |
GET |
/api/users/profile/{userId} |
๊น์์ฃผ |
์ ์ | ์ฌ์ฉ์ ์นด์นด์คํก ํ์๊ฐ์ |
GET |
/api/oauth/kakao/login |
๊น์์ฃผ |
๋ง์ง ์กฐํ |
์๊ตฐ๊ตฌ ๋ชฉ๋ก ์กฐํ | GET |
/api/city |
์ด์ง์ |
๋ง์ง ์กฐํ |
๋ง์ง ์์ธ ์ ๋ณด ์กฐํ |
GET |
/api/stores/:storeId |
์ด์ง์ |
ํ๊ฐ | ๋ง์ง ํ๊ฐ ์์ฑ | POST |
/api/reviews/:storeId |
์ด์ง์ |
๋ง์ง ์กฐํ |
์ธ๊ธฐ ๋ง์ง ์กฐํ | GET |
/api/stores/popular |
์ด์ง์ |
๋ง์ง ์กฐํ |
์ธ๊ธฐ ๊ธ์์น ๋ง์ง ์กฐํ |
GET |
/api/stores/rising |
์ด์ง์ |
๋ง์ง ์กฐํ |
์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ๋ง์ง ์กฐํ |
GET |
๊ฑฐ๋ฆฌ์ : /api/stores?lon=127.1108000763&lat=37.3503950812&range=1 ํ์ ์ : /api/stores?lon=127.1108000763&lat=37.3503950812&range=1&orderBy=rating |
์ ์งํฌ |
๋ง์ง ์กฐํ |
์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ๋ง์ง ์ถ์ฒ |
GET |
/api/stores/recommend?lon=127.1108000763&lat=37.3503950812 |
์ ์งํฌ |
๐ญ ์นด์นด์คํก Token์ ์ ์ฅํ๋ ๊ฒ vs ์ง์ Token์ ์์ฑํ๋ ๊ฒ ์ค ์ด๋ค๊ฒ ์ข์๊น?
- ์ฅ์
- ์นด์นด์ค ์ธก์์ ๋ฐํํ ํ ํฐ์ ์ด๋ฏธ ์ธ์ฆ๊ณผ ๊ถํ ๋ถ์ฌ๊ฐ ์๋ฃ๋ ์ํ์ด๊ธฐ ๋๋ฌธ์, ๋ณ๋์ ์ธ์ฆ ๋ก์ง์ ๊ตฌํํ์ง ์๊ณ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์๋ค.
- OAuth 2.0๊ณผ ๊ฐ์ ์ธ๋ถ ์๋น์ค ํ ํฐ์ ์ฌ์ฉํ๋ฉด ๋ณด์์ฑ์ด ๋ ๋๊ณ , ์ธ์ฆ ์๋ฒ๋ฅผ ์ด์ํ ํ์๊ฐ ์๋ค. ๋ํ, ์นด์นด์ค์์ ์ ๊ณตํ๋ ๋ณด์ ์ ์ฑ (ํ ํฐ ๊ฐฑ์ , ๋ง๋ฃ ๋ฑ)์ด ๊ทธ๋๋ก ์ ์ฉ๋๋ค.
- ๋จ์
- ์นด์นด์ค์ ํ ํฐ ๊ด๋ฆฌ ์ ์ฑ ์ ์์กดํด์ผ ํ๋ฏ๋ก, ํ ํฐ ๊ฐฑ์ ์ฃผ๊ธฐ๋ ๋ง๋ฃ ์ ์ฑ ๋ฑ์์ ์ ์ฐ์ฑ์ด ๋จ์ด์ง๋ค.
- ์นด์นด์ค ์ธ์ ๋ค๋ฅธ ๋ก๊ทธ์ธ ์๋จ์ ์ฌ์ฉํ ๊ฒฝ์ฐ(์: ์์ฒด ๋ก๊ทธ์ธ), ๋ค๋ฅธ ๋ฐฉ์์ ํ ํฐ ๊ด๋ฆฌ๊ฐ ํ์ํด์ง ์ ์๋ค.
- ์นด์นด์ค์์ ์ ๊ณตํ๋ ํ ํฐ์ API ์ฌ์ฉ์ ์ ํฉํ์ง๋ง, ๋ด๋ถ ์์คํ ์์ ์ฌ๋ฌ ์๋น์ค ๊ฐ์ ์ธ์ฆ์ด ํ์ํ๋ค๋ฉด ์ถ๊ฐ ๋ก์ง์ด ๋ณต์กํด์ง ์ ์๋ค.
- ์ฅ์
- ๋ ๋ฆฝ์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ ์ธ์ฆ ์๋จ์ด๋ฉฐ, ์ฌ์ฉ์ ์ ๋ณด(์ : ๊ถํ, ์ ํจ ๊ธฐ๊ฐ)๋ฅผ ์์ฒด์ ์ผ๋ก ํฌํจํ ์ ์๋ค. ๊ทธ๋์ ๋ง์ดํฌ๋ก์๋น์ค ํ๊ฒฝ์์ ๋น ๋ฅด๊ฒ ์ธ์ฆ์ ์ฒ๋ฆฌํ ์ ์๋ค.
- ์นด์นด์ค ์ธ์ ๋ค์ํ ๋ก๊ทธ์ธ ์๋จ์ ํตํฉ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ฉ์ดํ๋ฉฐ, ํ ํฐ ๋ฐ๊ธ ๋ฐ ๋ง๋ฃ ์ ์ฑ ์ ์ ์ฐํ๊ฒ ์ค์ ํ ์ ์๋ค.
- Refresh ํ ํฐ์ ํตํด ํ ํฐ ๋ง๋ฃ ์ ์๋ก์ด Access ํ ํฐ์ ์ฝ๊ฒ ๋ฐ๊ธํ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํ ์ ์๋ค.
- ๋จ์
- ์ธ์ฆ ์๋ฒ๋ฅผ ์ง์ ๊ด๋ฆฌํด์ผ ํ๋ฏ๋ก, ์ถ๊ฐ์ ์ธ ๋ณด์ ์ค์ (์: ํ ํฐ ์ํธํ, ์ ์ฅ์ ๊ด๋ฆฌ)์ด ํ์ํ๋ค.
- ํ ํฐ ๊ด๋ฆฌ์ ๋ณด์์ ๋ํ ์ถ๊ฐ์ ์ธ ์ฑ ์์ด ์๊ธฐ๋ฉฐ, ์๋ชป๋ ์ค์ ์ ๋ณด์ ์ทจ์ฝ์ ์ด ์๊ธธ ์ ์๋ค.
- ์นด์นด์ค API์์ ๋ฐ๊ธ๋ ํ ํฐ์ ์ฌ์ฉํด ์ด๊ธฐ ์ธ์ฆ์ ์งํํ๊ณ , ์ดํ์๋ ์์ฒด์ ์ผ๋ก ๋ฐ๊ธํ JWT๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ์์ด ์๋ค.
- ์นด์นด์ค API์ ํตํฉ๊ณผ ๋ด๋ถ์ ์ธ ์ฌ์ฉ์ ์ธ์ฆ์ ๋ชจ๋ ์์ ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
- ์ผ๋ฐ์ ์ผ๋ก ์ธ๋ถ OAuth ์ธ์ฆ์ ์ฌ์ฉํ ๋ ์ธ๋ถ Access/Refresh ํ ํฐ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ณด์๊ณผ ํธ์์ฑ์ ๋์ผ ์ ์๋ค.
- ๋ด๋ถ์ ์ผ๋ก ์ฌ๋ฌ ์ธ์ฆ ์๋จ์ ๊ด๋ฆฌํด์ผ ํ๊ฑฐ๋, ํ ํฐ ์ฌ์ฉ ๋ฒ์๊ฐ ๋ ๋์ ๊ฒฝ์ฐ์๋ JWT๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ ๋ฆฌํ ์ ์๋ค.
- ๋ฐ๋ผ์ ์นด์นด์ค ํ ํฐ์ ์ฌ์ฉํ์ฌ OAuth ์ธ์ฆ์ ์๋ฃํ ํ, ๋ด๋ถ ์์คํ ์์๋ ์์ฒด JWT ํ ํฐ์ ๋ฐ๊ธํ์ฌ ๊ด๋ฆฌํ๋ ๋ฐฉ์์ด ๋ณด์์ฑ์ ์ ์งํ๋ฉด์ ์ ์ฐํ ํ ํฐ ๊ด๋ฆฌ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
๐ญ ์นด์นด์คํก ๋ก๊ทธ์ธ ์ ํจ์ค์๋ ์ ๋ณด๋ ์ฃผ์ง ์๋๋ค. ์ด๋ป๊ฒ ๊ด๋ฆฌํด์ผ ํ ๊น?
- ์นด์นด์ค API๋ก ๋ก๊ทธ์ธํ๋ ์ฌ์ฉ์์ ๊ฒฝ์ฐ, ๋ณ๋์ ๋น๋ฐ๋ฒํธ ์์ด ์์ ๋ก๊ทธ์ธ๋ง์ผ๋ก ์ธ์ฆ์ด ์ด๋ฃจ์ด์ง๋๋ก ์ค์ ํ ์ ์๋ค. ์ด๋, ์์ ๋ก๊ทธ์ธ์ผ๋ก ๋ค์ด์จ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐ๋ก ๊ด๋ฆฌํ๊ณ , ๋น๋ฐ๋ฒํธ๋ ๋น์๋๋ค.
- ์์ ๋ก๊ทธ์ธ๊ณผ ์ผ๋ฐ ๋ก๊ทธ์ธ์ ๋ชจ๋ ์ฌ์ฉํด์ผ ํ ๊ฒฝ์ฐ์๋ ๊ตฌ๋ถํด ๊ด๋ฆฌํ๋ ๊ฒ์ด ํ์ํ๋ค. ์๋ฅผ ๋ค์ด, ์นด์นด์ค ๋ก๊ทธ์ธ์ผ๋ก ์ฒ์ ํ์๊ฐ์ ์ ์์ ๋ก๊ทธ์ธ ํ๋๊ทธ๋ฅผ ์ค์ ํ๊ณ , ์์ฒด ๋ก๊ทธ์ธ ์ ๋น๋ฐ๋ฒํธ๋ฅผ ํ์์ ์ผ๋ก ์ ๋ ฅ๋ฐ๋ ์์ผ๋ก ๊ตฌํํ ์ ์๋ค.
- ์ธ๋ถ OAuth ๋ก๊ทธ์ธ ์ฑ๊ณต ํ ๋น๋ฐ๋ฒํธ ์ค์ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธํ์ฌ ์ฌ์ฉ์๊ฐ ์ง์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ค์ ํ๋๋ก ์ ๋ํ๋ค. ์ฌ์ฉ์๋ ๋ก๊ทธ์ธ ์ ์นด์นด์ค ์์ ๋ก๊ทธ์ธ ์ธ์๋ ์์ฒด ๋ก๊ทธ์ธ ์์คํ ์ ์ด์ฉํ ์ ์๋๋ก ์ ํ์ ํญ์ ๋ํ ์ ์๋ค.
- ์ฅ์
- ํต์ผ๋ ๊ด๋ฆฌ : ํ๋์ ์ธ์ฆ ์ฒด๊ณ๋ก ๊ด๋ฆฌ๊ฐ ํต์ผ๋ ์ ์๋ค.
- ์ด์ค ์ธ์ฆ ๊ฐ๋ฅ : ์์ ๋ก๊ทธ์ธ ๋ฟ๋ง ์๋๋ผ ๋น๋ฐ๋ฒํธ ๊ธฐ๋ฐ์ ์ธ์ฆ์ ์ํ๋ ๊ฒฝ์ฐ ์ ์ฐํ๊ฒ ์ ํ์ด ๊ฐ๋ฅํ๋ค. ์์ฒด ๋ก๊ทธ์ธ์ด ๊ฐ๋ฅํ๋ค.
- ๋จ์ ๋ฐ ์ฃผ์์
- ๋ณด์ ๋ฌธ์ : ๋๋ค ์์ฑ๋ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ง์ฝ ์ ๋ฌํ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ์ ๋ฌํ๊ณ ๊ด๋ฆฌํ ์ง๊ฐ ๋ฌธ์ ์ด๋ค. ๋น๋ฐ๋ฒํธ๋ ์ ๋ ๋ ธ์ถ๋์ด์๋ ์ ๋๋ฉฐ, ์ ๋ฌ ๊ณผ์ ์์์ ๋ณด์์ด ๋งค์ฐ ์ค์ํ๋ค.
- ์๋ฏธ ์๋ ๋น๋ฐ๋ฒํธ ๊ด๋ฆฌ : ์์ ๋ก๊ทธ์ธ์ ์ฌ์ฉํ ์ฌ์ฉ์์๊ฒ ๋น๋ฐ๋ฒํธ๊ฐ ํ์ํ์ง ์์ ๊ฒฝ์ฐ, ๊ตณ์ด ๋๋ค ๋น๋ฐ๋ฒํธ๋ฅผ ์์ฑํ๊ณ ์ ์ฅํ๋ ๊ฒ์ ๋ถํ์ํ ์์ ์ผ ์ ์๋ค. ์ฌ์ฉ์ ์ธ์ฆ์ ์ด๋ฏธ ์นด์นด์ค์์ ๋ณด์ฅ๋๋ฏ๋ก, ๋ถํ์ํ ๋ณต์ก์ฑ์ ๋ํ ๊ฐ๋ฅ์ฑ์ด ์๋ค.
๐ญย ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ JDBC Batch Insert ๋ง์ผ๋ก ์ถฉ๋ถํ ๊น?
์ด๊ธฐ์ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ ๋, ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ณ ์ฒ๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ JDBC Batch Insert๋ฅผ ํ์ฉํ๋ค. ๋๋์ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ์ฝ์ ํ ์ ์์ด ํจ์จ์ ์ด๋ผ๊ณ ํ๋จํ๊ธฐ ๋๋ฌธ์ด๋ค.
ํ์ง๋ง ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ์๋ํ ์ดํ, JDBC๋ฅผ ์ฌ์ฉํ ๊ธฐ์กด ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ ๋ฐฉ์์์ ๋นํจ์จ์ฑ์ด ๋๋ฌ๋ฌ๋ค. ๊ฐ ๋ ์ฝ๋์ ๋ชจ๋ ํ๋๋ฅผ ์ผ์ผ์ด ๋น๊ตํ๊ณ ์ ๋ฐ์ดํธํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. ์ด๋ก ์ธํด ๋ถํ์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ, ๋ณต์กํ ์ฝ๋ ๋ก์ง, ๋๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ ์ฑ๋ฅ ์ ํ ๋ฑ์ ๋ฌธ์ ๊ฐ ์์๋๋ค.
๊ทธ๋์ ๋ค๋ฅธ ๋ก์ง์ ๊ณ ๋ฏผํ๋ ์ค JPA ๋ณ๊ฒฝ ๊ฐ์ง ๊ธฐ๋ฅ์ ์ ๋ต์ ์ผ๋ก ํ์ฉํ๊ธฐ๋ก ํ๋ค. JPA๋ ์ํฐํฐ์ ์ํ ๋ณํ๋ฅผ ์๋์ผ๋ก ์ถ์ ํ์ฌ ํ์ํ ์ ๋ฐ์ดํธ๋ง ์ํํ๋ค. ์ด๋ฅผ ํตํด ์ฝ๋ ๋ณต์ก์ฑ ๊ฐ์, ์ต์ ํ๋ ์ฟผ๋ฆฌ ์์ฑ, ๊ฐ๋ฐ ์์ฐ์ฑ ํฅ์ ๋ฑ์ ์ด์ ์ ์ป์ ์ ์์๋ค. ๋ํ JPA์ ์ ๋ํฌ ํค ๊ธฐ๋ฅ์ผ๋ก ๋ฐ์ดํฐ ์ค๋ณต ์ฝ์ ๋ฌธ์ ๋ ํด๊ฒฐํ๋ค.
JDBC Batch Insert์ JPA ๋ณ๊ฒฝ ๊ฐ์ง๋ฅผ ๊ฒฐํฉํ ํ์ด๋ธ๋ฆฌ๋ ์ ๊ทผ ๋ฐฉ์์ ์ฑํํ๋ค:
- JDBC: ์๋ก์ด ๋๋ ๋ฐ์ดํฐ ์ฝ์ ์ ํ์ฉ
- JPA: ๊ธฐ์กด ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ์ ํ์ฉ
์ด๊ธฐ JDBC Batch๋ง ์ ์ฉํ์ ๋์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์๊ฐ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ํ์ด๋ธ๋ฆฌ๋ ๋ฐฉ์์ ์ ์ฉํ ํ์ ์ฒ๋ฆฌ ์๊ฐ์ด๋ค.
๋ฐ์ดํฐ ์ฒ๋ฆฌ ์๊ฐ์ด ์ฝ 23์ด์์ 15์ด๋ก ์ฝ 34.8% ๋จ์ถ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ด๋ ์ค๊ตญ์ง ์นดํ ๊ณ ๋ฆฌ ํ๋๋ง์ ๋์์ผ๋ก ํ ํ ์คํธ ๊ฒฐ๊ณผ์ด๋ค. ์ค์ ์๋น์ค์์๋ 10๊ฐ ์ด์์ ๋ค์ํ ์นดํ ๊ณ ๋ฆฌ๋ฅผ ์์งํ๋ฏ๋ก, ์ด ์ต์ ํ ์ ๋ต์ ์ ์ฒด ์์คํ ์ ์ ์ฉํ ๊ฒฝ์ฐ ์ฑ๋ฅ ๊ฐ์ ํจ๊ณผ๊ฐ ๋์ฑ ๊ทน๋ํ๋ ๊ฒ์ผ๋ก ์์๋๋ค.
๐ญย ๋ฐ์ดํฐ ์๋ํ ์๊ฐ์ ์ด๋ป๊ฒ ์ค์ ํ๋ ๊ฒ ์ข์๊น?
- ์๋ฒ๋ถํ๋ฅผ ๋ง์ผ๋ฉด์ ๋ฐ์ดํฐ์ ์ ์ ๋ ์ ์งํ๋ ๋ฒ
- ๊ณต๊ณต๋ฐ์ดํฐ ๊ฐฑ์ ์ฃผ๊ธฐ์ ๋ฐ๋ผ ๋ฐ์ดํฐ ์๋ํ
- ๊ณต๊ณต๋ฐ์ดํฐ์ ์ผ์ฃผ์ผ ๊ฐฑ์ ์ฃผ๊ธฐ๋ฅผ ์ฐธ๊ณ ํด ์๋น์ค๋ 1์ฃผ์ผ ๋จ์๋ก ์ค์
- ๋๋ถ๋ถ์ด ์ ์ฌ๋ฉ๋ด๋ฅผ ์ฐพ๋ ์ด์ฉ์์์ ๊ณ ๋ คํด ํ์ผ ์๋ฒฝ ์๊ฐ๋๋ก ์ค์
- ๊ณต๊ณต๋ฐ์ดํฐ๊ฐ ์์ฃผ ๊ฐฑ์ ๋์ง ์๋๋ค๋ ์ ์ ๊ณ ๋ ค
- ๊ณต๊ณต๋ฐ์ดํฐ ์์ง๊ณผ ์ ์ฒ๋ฆฌ ์๊ฐ์ ๋ถ๋ฆฌํด ์๋ฒ ๋ถํ ๋ฐฉ์ง
๐ญ ์ธ๊ธฐ ๋ง์ง์ ๋งค๋ฒ ์กฐํํ๋ ๋ฐฉ๋ฒ ๋ง๊ณ ๋ค๋ฅธ ๋ฐฉ๋ฒ ์์๊น?
ํ์๋ค๊ณผ ์ธ๊ธฐ ๋ง์ง์ ์กฐํํ๋ ๊ธฐ์ค์ ํ์ ๊ณผ ๋ฆฌ๋ทฐ ๊ฐ์๋ก ์ ํ๋ค.
์ดํ ๊ตฌํ ๋ฐฉ๋ฒ์ ๊ณ ๋ฏผํ๋ฉด์ ๊ฐ์ฅ ๊ฑฑ์ ๋๋ ๊ฒ์ ์ธ๊ธฐ ๋ง์ง์ ๊ฒฝ์ฐ ํ๋ฃจ๋ ์ผ์ฃผ์ผ ๋จ์๋ก ๋ณด์ฌ์ค ํ ๋ฐ DB์ ์ ์ฅ๋ ๋ชฉ๋ก์ ์กฐํํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ๋งค๋ฒ ์ฟผ๋ฆฌ๋ฅผ ์คํํด์ผ ํด์ ์ฑ๋ฅ ๋ฉด์์ ๋นํจ์จ์ ์ผ ๊ฒ ๊ฐ๋ค๋ ์ ์ด์๋ค.
๊ทธ๋์ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ ์ค Redis์ ์บ์๋ฅผ ์ฌ์ฉํ๋ ์ ๋ต์ ๋ฐ๊ฒฌํ๋ค.
์บ์๋ DB์ ์์ฃผ ์ ๊ทผํด์ ๊ฐ์ ธ์ค๋ ๋ฐ์ดํฐ๋ฅผ ์์๋ก ์ ์ฅํด ๋ ๋ค, ์ดํ ๋์ผํ ๋ฐ์ดํฐ ์์ฒญ์ด ๋ค์ด์์ ๋ DB์ ์ ๊ทผํ์ง ์๊ณ ๋ฏธ๋ฆฌ ์ ์ฅํด ๋ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๋ ๋ฐฉ์์ด๋ค.
์ธ๊ธฐ ๋ง์ง์ ์ผ์ ๊ธฐ๊ฐ ๋์ ๊ฐ์ ๊ฐ์ ์กฐํํ๊ธฐ ๋๋ฌธ์ ์บ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ฟผ๋ฆฌ ์คํ์ ์ค์ผ ์ ์์ด์ ์ ์ฉํ๊ธฐ ์๋ง์ ๋ฐฉ๋ฒ์ด๋ผ๋ ์๊ฐ์ด ๋ค์๋ค.
์บ์์ ์ ํจ๊ธฐ๊ฐ์ ํ๋ฃจ๋ก ์ค์ ํด ์ธ๊ธฐ ๋ง์ง์ด ํ๋ฃจ ๋จ์๋ก ๋ณ๋๋๊ฒ ์ค์ ํ๋ค.
์บ์๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ ์๋ต ์๊ฐ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ์บ์๋ฅผ ์ฌ์ฉํ ํ์ ์๋ต ์๊ฐ์ด๋ค.
์๋ต ์๊ฐ์ด 67ms์์ 16ms๋ก ์ฝ 75% ๋จ์ถ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์์๋ก ์ ์ ๋ฐ์ดํฐ๋ก ํ ์คํธ ํ์ ๋ ๋์จ ๊ฒฐ๊ณผ์ด๋ค. ๋์ฉ๋ ๋ฐ์ดํฐ๋ก ์บ์๋ฅผ ์ ์ฉํ๋ค๋ฉด ์ฑ๋ฅ ๋ฉด์์ ๋ ํจ๊ณผ์ ์ผ ๊ฒ์ด๋ผ ์๊ฐํ๋ค.
๐ญ ์ธ๊ธฐ ๊ธ์์น ๋ง์ง ์กฐํ๋ ์ด๋ค ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํ ๊น?
์ธ๊ธฐ ๊ธ์์น ๋ง์ง ์กฐํ ๊ธฐ์ค์ ์ ๋ ์์ฑ๋ ๋ฆฌ๋ทฐ ๊ฐ์๋ก ์ ํ๋ค.
๊ณ ๋ฏผํ ๊ตฌํ ๋ฐฉ๋ฒ์ 2๊ฐ์ง. store ์ํฐํฐ์ ํ๋ฃจ๋์ ์ถ๊ฐ๋ ๋ฆฌ๋ทฐ ๊ฐ์ ๋ด๋ ํ๋๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ๊ณผ review ์ํฐํฐ์ ์์ฑ์ผ ํ๋๋ฅผ ์ถ๊ฐํด ์ ๋ ์์ฑ๋ ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ ์กฐํํ๋ ๋ฐฉ๋ฒ.
๋จผ์ ํ๋ฃจ๋์ ์ถ๊ฐ๋ ๋ฆฌ๋ทฐ ๊ฐ์ ๋ด๋ ํ๋๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ์กฐํ ์ ๋ณ๋์ ๊ณ์ฐ์ด ํ์๊ฐ ์์ด์ ์ฑ๋ฅ ๋ฉด์์ ์ข๊ณ , ์ฟผ๋ฆฌ๋ ๊ฐ๋จํด์ง๋ค๋ ์ฅ์ ์ด ์์๋ค. ํ์ง๋ง ๋ฆฌ๋ทฐ๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค ํ๋๋ฅผ ์ ๋ฐ์ดํธํด์ค์ผ ํ๊ณ , ๋งค์ผ ํด๋น ํ๋๋ฅผ 0์ผ๋ก ์ด๊ธฐํํด์ค์ผ ํ๋ ๋ฒ๊ฑฐ๋ก์์ด ์กด์ฌํ๋ค. store ๋ฐ์ดํฐ๊ฐ ์ ๋ค๋ฉด ๊ด์ฐฎ์ ๋ฐฉ๋ฒ์ด์๊ฒ ์ง๋ง ๋์ฉ๋ ๋ฐ์ดํฐ์ ์ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์๋ ๊ฒ์ด๋ผ๋ ์๊ฐ์ด ๋ค์๋ค.
๋ฐ๋ผ์ review ์ํฐํฐ์ ์์ฑ์ผ ํ๋๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ์ฑํํ๋ค. ๋ฆฌ๋ทฐ๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค ์ถ๊ฐ์์ ์ ํ ํ์๊ฐ ์์ด ์ฝ๊ธฐ ์ฑ๋ฅ๋ง ๊ฐ์ ํ๋ฉด ๋๋ค๋ ์ด์ ์ด ์์ด์๋ค.
๋ค์์ผ๋ก ๊ณ ๋ฏผํ๊ฒ ๋ ์ฝ๊ธฐ ์ฑ๋ฅ ๊ฐ์ ๋ฐฉ๋ฒ. ํด๋น ๋ฐฉ๋ฒ์ ์กฐํ ์ ๋ฆฌ๋ทฐ์ ์์ฑ ๋ ์ง๋ฅผ ๊ธฐ์ค์ผ๋ก ์ง๊ณํด์ผ ํ๋ฏ๋ก ์ฑ๋ฅ์ด ๋น๊ต์ ๋๋ฆฌ๋ค๋ ๋จ์ ์ด ์กด์ฌํ๋ค. ๋ฐ๋ผ์ Redis ์บ์๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค. ์บ์ ๊ฐฑ์ ์์ ์๋ง ์กฐํํ๊ฒ ๋๋ฏ๋ก ์ฑ๋ฅ ๋ถ๋ด์ด ๋ํ ๊ฒ์ด๋ผ๊ณ ํ๋จํ๋ค. ๋ํ, ์ ๋ ์ ๊ธฐ๋ก์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฌํ๊ธฐ ๋๋ฌธ์ ์บ์ ์ฌ์ฉ์ด ์๋ฏธ๊ฐ ์์ผ๋ฆฌ๋ผ๋ ์๊ฐ์ด ๋ค์๋ค.
๐ญ ์ฌ์ฉ์ ์์น์ ๋ง์ง ๊ฐ์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ด๋ค ๊ฒ์ด ๊ฐ์ฅ ์ ํฉํ ๊น?
์ฒ์ ์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ๋ง์ง ์กฐํ ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ ๋, ๋ ์ง๋ฆฌ์ ์ขํ ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ๋ ๋ฐฉ๋ฒ์ ์ง์คํ๋ค.
๊ฒ์์ ํตํด ๋ ์ง์ ๊ฐ์ ๊ตฌ๋ฉด ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ๋ ์ํ ๊ณต์์ธ โํ๋ฒ์ฌ์ธ ๊ณต์โ์ ์๊ฒ ๋์๊ณ , ์ด๋ฅผ Querydsl๊ณผ ํจ๊ป ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์์น์์ ์ฃผ์ด์ง ๋ฒ์ ๋ด์ ๋ง์ง์ ๊ฒ์ํ ์ ์์๋ค.
ํ์ง๋ง ์ฟผ๋ฆฌ๊ฐ ๋ณต์กํด์ง๊ณ , ์ ์ง๋ณด์๊ฐ ์ด๋ ค์ธ ๊ฒ ๊ฐ๋ค๋ ํ๋จ์ด ๋ค์ด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฐพ๊ธฐ๋ก ํ๋ค.
๊ณต๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ ๊ณตํ๋ ๊ณต๊ฐ ๋ฐ์ดํฐ ํ์ ๊ณผ ๊ณต๊ฐ ํจ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค.
๊ณต๊ฐ ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ ํํ ์ง๋ฆฌ์ ๊ฑฐ๋ฆฌ ๊ณ์ฐ์ด ๊ฐ๋ฅํ๋ฉฐ, ๊ณต๊ฐ ์ธ๋ฑ์ค๋ฅผ ์ ์ฉํ๋ฉด ์ฑ๋ฅ๋ ํฌ๊ฒ ํฅ์์ํฌ ์ ์๋ค.
์ฟผ๋ฆฌ์ ์ด๋ค ๊ณต๊ฐ ํจ์๋ฅผ ์ฌ์ฉํ ์ง ๊ณ ๋ฏผํ๋ค.
ST_DISTANCE
: SRID 4326์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ํ๋ฒ์ฌ์ธ ๊ณต์๊ณผ ์ ์ฌํ ๊ณ์ฐ์ ์ํํ์ฌ ์ ํฉํด ๋ณด์์ง๋ง, ๊ณต๊ฐ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ ์ ์์ด ์ ํํ์ง ์์๋ค.ST_Contains
+ST_Buffer
: ๊ณต๊ฐ ์ธ๋ฑ์ค๋ฅผ ์ ์ฉํ ์ ์๋ ์ด ๋ฐฉ๋ฒ์ ์ ํํ๋ค.
-
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ ๊ฒฝ๋์ ์๋๋ฅผ ํ์ฉํ์ฌ, ๊ณต๊ฐ ๋ฐ์ดํฐ ํ์ ์ธ Point๋ฅผ ์ฌ์ฉํด ์์น(location) ๋ฐ์ดํฐ๋ฅผ ๊ตฌ์ฑํ๋ค.
-
ST_Contains
์ST_Buffer
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋ค.// ์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ๋ง์ง ์กฐํ ๋ชฉ๋ก - ๊ฑฐ๋ฆฌ์์ผ๋ก ์ ๋ ฌ @Query("SELECT s FROM Store s " + "WHERE ST_Contains(ST_Buffer(:userLocation, :meterRange), s.location) " + // ST_Buffer์ ST_Contains๋ก spatial index ํ์ฉ "ORDER BY ST_Distance(s.location, :userLocation) ASC") // ์ฌ์ฉ์์ ๊ฐ๊น์ด ๋ง์ง๋ถํฐ ์ ๋ ฌ
๐ญ ์ฌ์ฉ์ ์์น ๊ธฐ๋ฐ ๋ง์ง ์ถ์ฒ์ ์ด๋ค ๊ธฐ์ค์ผ๋ก ์ถ์ฒ์ ์ ํ ๊น?
๋ง์ง ์ถ์ฒ์ ์ํ ์ด๊ธฐ ๊ณ์ฐ์์ ํ์ * 0.7 + ๋ฆฌ๋ทฐ ๊ฐ์ * 0.3
์ด์๋ค.
ํ์ง๋ง ๋ฆฌ๋ทฐ ๊ฐ์์ ๋ฒ์๊ฐ ๋๋ฌด ๋์ด ํฌ๊ธฐ ์กฐ์ ์ด ํ์ํ๋ค๊ณ ์๊ฐํ๋ค.
์กฐ์ ์ ์ํ ๊ณ์ฐ์์ ๋ง๋ค๊ธฐ ์ํด์ ๋ค์ด๋ฒ ์ง๋ ์ฑ์์ ๋ง์ง ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ ์กฐ์ฌํ๋ค.
๋ํ ํ๋์ฐจ์ด์ฆ ๋งค์ฅ์ ๊ฒฝ์ฐ ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ 5,000๊ฐ๋ฅผ ์ฝ๊ฒ ๋๊ธฐ๊ณ , 10,000๊ฐ ์ด์์ธ ๊ณณ๋ ์์๋ค.
๋ฐ๋ฉด, ๊ฐ์ธ์ด ์ด์ํ๋ ๋ง์ง์ ๋ณดํต 1,000๊ฐ์์ 2,000๊ฐ ์ฌ์ด์ด๋ฉฐ, ๊ฐ๋ 2,000๊ฐ๋ฅผ ๋๋ ๊ฒฝ์ฐ๋ ์์ง๋ง 3,000๊ฐ ์ด์์ ๋๋ฌผ์๋ค.
๋ฐ๋ผ์ ๋ฆฌ๋ทฐ ๊ฐ์๋ฅผ 0๊ณผ 1 ์ฌ์ด ๊ฐ์ผ๋ก ์ ๊ทํํ๊ธฐ ์ํด 3,000์ ๊ธฐ์ค์ผ๋ก ์ผ๊ธฐ๋ก ํ๋ค.
- ๊ณ์ฐ์ =ย
ํ์ * 0.7 + (๋ฆฌ๋ทฐ ๊ฐ์ / 3000) * 0.3
- ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ 3,000๊ฐ ์ด๊ณผํ ๊ฒฝ์ฐ,ย
(๋ฆฌ๋ทฐ ๊ฐ์ / 3000)
์ 1๋ก ์ฒ๋ฆฌํ๋ค. - ๊ณ์ฐ์ ๊ฒฐ๊ณผ๊ฐ 3.0 ์ด์์ด๋ฉด ์ถ์ฒํ๋ ๋ง์ง์ผ๋ก ์ ํ๋ค.
double rating = 4.2; // ํ์
int reviewCount = 1000; // ๋ง์ง์ ๋ฆฌ๋ทฐ ๊ฐ์
int maxReviewCount = 3000; // ์ ๊ทํ ํ ๋ฆฌ๋ทฐ ๊ฐ์์ ์ต๋๊ฐ
// ๋ฆฌ๋ทฐ ๊ฐ์ ์ ๊ทํ (0~1 ์ฌ์ด ๊ฐ์ผ๋ก ๋ณํ)
// ๋ฆฌ๋ทฐ ๊ฐ์๊ฐ 3000์ ์ด๊ณผํ๋ฉด normalizedReviewCount๋ 1๋ก ์ฒ๋ฆฌ
double normalizedReviewCount = reviewCount > maxReviewCount ? 1.0 : (double) reviewCount / maxReviewCount;
// ์ต์ข
์ ์ ๊ณ์ฐ (ํ์ ์ 70%, ๋ฆฌ๋ทฐ ๊ฐ์์ 30% ๊ฐ์ค์น)
// score = 3.04
double score = (rating * 0.7) + (normalizedReviewCount * 0.3);
โก ์นด์นด์ค ๋ก๊ทธ์ธ DB ๊ณ์ ์ญ์
- ์นด์นด์ค ๋ก๊ทธ์ธ ์ฑ๊ณต ์ดํ ๊ณ์ ํ์๊ฐ์ ์ฌ์๋ ์ค MySQL์์ ํด๋น ๊ณ์ ์ญ์ ๊ฐ ๋์ง ์๋ ๋ฌธ์ ๋ฐ์
- Safe Lock์ด ๊ฑธ๋ ค์ ธ ์์ด์ ํ ์คํธํ ๊ณ์ ์ด ์ญ์ ๊ฐ ๋์ง ์์๋ ๊ฒ
- Safe Mode๋ฅผ ํด๋น ์ฟผ๋ฆฌ๋ฌธ์ ์คํํ๋ ๋์ ๊ป๋ค๊ฐ ์ผ์ค
-- Safe update mode ๋นํ์ฑํ
SET SQL_SAFE_UPDATES = 0;
-- DELETE ์ฟผ๋ฆฌ ์คํ
DELETE FROM users WHERE social_type = 'KAKAO';
-- Safe update mode ๋ค์ ํ์ฑํ
SET SQL_SAFE_UPDATES = 1;
โก Spring Boot 3.0 ์ด์ Spring Batch ์ค๋ฅ
- ๋ฉํ ๋ฐ์ดํฐ ํ ์ด๋ธ ์์ฑ ์ค๋ฅ ๋ฐ์์ผ๋ก Job์ด ์คํ๋์ง ์์
- ์ฌ๋ฌ ๊ฐ์ Job ์์ฑ ์ ์คํ ์ค๋ฅ
- Spring Batch 5.0๊ณผ Spring Boot 3.0์ ๋ณ๊ฒฝ์ฌํญ์ผ๋ก ์๋ ์ค์ ๋นํ์ฑํ
- @EnableBatchProcessing springBoot 3.0 ๊ถ์ฅ x โ ์๋ ์ค์ ๋ชจ๋ ๋นํ์ฑํ
- ์๋ก์ด
BatchConfig
ํด๋์ค ์์ฑ
@Configuration
@EnableConfigurationProperties(BatchProperties.class)
public class BatchConfig {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.batch.job", name = "enabled", havingValue = "true", matchIfMissing = true)
public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer,
JobRepository jobRepository, BatchProperties properties) {
JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobLauncher, jobExplorer, jobRepository);
String jobNames = properties.getJob().getName();
if (StringUtils.hasText(jobNames)) {
runner.setJobName(jobNames);
}
return runner;
}
}
DataPipeJobConfig
์ยOpenApiJobConfig
ย ์์ :@EnableScheduling
ย ์ด๋ ธํ ์ด์ ์ ๊ฑฐ (์ค์ผ์ค๋ฌ ํด๋์ค๋ก ์ด๋)@Configuration
ย ์ ์ง
DataPipeJobScheduler
์์
@Component
@RequiredArgsConstructor
@EnableScheduling
@Slf4j
public class DataPipeJobScheduler {
private final JobLauncher jobLauncher;
private final Job openApiJob;
private final Job dataPipeJob;
@Scheduled(cron = "0 0 3 * * 1") // ๋งค์ฃผ ์์์ผ ์๋ฒฝ 3์ 1๋ฒ
public void collectRawData(){
runJob(openApiJob,"๊ณต๊ณต๋ฐ์ดํฐ ์์ง");
}
@Scheduled(cron = "0 0 5 * * 1") // ๋งค์ฃผ ์์์ผ ์๋ฒฝ 5์ 1๋ฒ
public void processedDataUpdate(){
runJob(dataPipeJob,"์ด์ ๋ฐ์ดํฐ ์ ์ฒ๋ฆฌ");
}
private void runJob(Job job, String jobDescription) {
log.info("{} Job์ ์คํํฉ๋๋ค.",jobDescription);
try {
// ๊ฐ ์คํ๋ง๋ค ๊ณ ์ ํ JobParameters ์์ฑ
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
// ์์
์คํ
JobExecution jobExecution = jobLauncher.run(job, jobParameters);
// ์์
์คํ ๊ฒฐ๊ณผ
log.info(" {} Job ๊ฒฐ๊ณผ์
๋๋ค: {}", jobDescription,jobExecution.getStatus());
} catch (Exception e) {
// ์์ธ ๋ฐ์ ์
log.error("{} Job์ ์์ธ๊ฐ ๋ฐ์ํ์ต๋๋ค: {}",jobDescription, e.getMessage());
}
}
}
application-secret.yml
์์
batch:
job:
enabled: false #์ดํ๋ฆฌ์ผ์ด์
์์ ์ ์๋ ์์ ๋ฐฉ์ง
jdbc:
initialize-schema: always
- ๋ฉํํ ์ด๋ธ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ
- ์ฌ๋ฌ ๊ฐ์ Job์ด ์ค์ผ์ค๋ฌ ์ค์ ์ ๋ง๊ฒ ์ฑ๊ณต์ ์ผ๋ก ์คํ
โก EC2 ํ๊ฒฝ์์ Redis Docker ์ปจํ ์ด๋์ Spring Boot ์ฐ๊ฒฐ ์ค๋ฅ
- EC2 ๋ฐฐํฌ ํ๊ฒฝ์์ Redis cache๋ฅผ ์ฌ์ฉํ API ์์ฒญ ๋ ๋ฆด ๊ฒฝ์ฐ 500 ์๋ฌ ๋ฐ์๊ณผ ํจ๊ป Connection refused ์ค๋ฅ ๋ฐ์
- redis ๋น๋ฐ๋ฒํธ ์ค์ ๋ฌธ์
- redis host ์ค์ ๋ฌธ์
-
redis ๋น๋ฐ๋ฒํธ๋ฅผ ์ค์ ํด์ฃผ์ง ์์์ application-secret.yml์ redis ๋น๋ฐ๋ฒํธ ์ค์ ์ ํด์ค ํ ๋ค์ ๋ฐฐํฌํจ
data: redis: password: [redis ๋น๋ฐ๋ฒํธ]
โก๏ธ ๊ทธ๋ฌ๋ ์ค์ ํด์ค ํ ๋ค์ API ์์ฒญ ๋ณด๋ด๋ ๋๊ฐ์ ์ค๋ฅ ๋ฐ์
-
๋ก์ปฌ ํ๊ฒฝ์์๋ ์ ์๋ํ์ง๋ง EC2 ํ๊ฒฝ์์๋ ์ค๋ฅ๊ฐ ๋๋ ๊ฒ์ด๋ผ๋ฉด host ๋ฌธ์ ์ผ ์ ์๋ค๊ณ ์๊ฐํจ โ EC2 ์ธ์คํด์ค ๋ด๋ถ์์ redis ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, redis host๋ฅผ EC2 IP๋ก ์ค์ ํ ๋ค์ ๋ฐฐํฌํจ
data: redis: password: [redis ๋น๋ฐ๋ฒํธ] host: [EC2 IP]
- redis cache๋ฅผ ์ฌ์ฉํ API ์ ์ ์๋
โก Point ์๋ฃํ๊ณผ ๊ณต๊ฐ ํจ์๋ฅผ ์ฌ์ฉํ ๋ SRID ์ค์
์ค๋ฅ ๋ฉ์์ง
java.sql.SQLException: Binary geometry function st_contains given two geometries of different srids: 0 and 4326, which should have been identical
์ฟผ๋ฆฌ์์๋ ๊ณต๊ฐ ํจ์(ST_Contains, ST_Distance)์ location, myLocation์ ์ฌ์ฉํด์ ์ฌ์ฉ์์ ์์น์ ๋ง์ง์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ๋ค.
ํด๋น ์ค๋ฅ๋ ST_Contains
ํจ์๊ฐ SRID๊ฐ ๋ค๋ฅธ ๋ ๊ฐ์ geometry ๊ฐ์ฒด๋ฅผ ๋น๊ตํ๋ ค๊ณ ํ ๋ ๋ฐ์ํ๋ ์ค๋ฅ์ด๋ค.
ST_Contains
ํจ์๋ ๋ geometry๊ฐ ๋์ผํ SRID(Spatial Reference System Identifier)๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ์๋ํ๋ค.
์ด๋ฐ ๊ฒฝ์ฐ ์ด๋ค geometry์ SRID๋ 4326์ผ๋ก ์ค์ ๋์ง๋ง, ๋ค๋ฅธ ํ๋์ SRID๋ 0์ผ๋ก ๋์ด ์์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
Store ์ํฐํฐ ํ์ผ์์ location ํ๋๋ฅผ ์ ์ํ ๋ SRID๋ฅผ 4326์ผ๋ก ์ค์ ํ๋ค.
ํ์ง๋ง StoreService ํ์ผ์์ myLocation ์ธ์คํด์ค๋ฅผ ์ ์ํ ๋ SRID ์ค์ ์ด ๋๋ฝ๋์ด ์์ด, ์๋ ์ฝ๋์ ๊ฐ์ด SRID๋ฅผ ์ค์ ํด ์ฃผ์๋ค.
Point myLocation = geometryFactory.createPoint(new Coordinate(lon, lat));
// ์๋ ์ค์ ์ ์ถ๊ฐํ์ฌ ๋ฌธ์ ํด๊ฒฐ
myLocation.setSRID(4326); // SRID 4326 (WGS 84 ์ขํ๊ณ)๋ก ์ค์