0502 ~ 0515
# 0502 ~ 0515
# 0502 - fetch join vs join
# ์ผ๋ฐ Join
- Fetch Join๊ณผ ๋ฌ๋ฆฌ ์ฐ๊ด Entity์ Join์ ๊ฑธ์ด๋ ์ค์ ์ฟผ๋ฆฌ์์ SELECT ํ๋ Entity๋ ์ค์ง JPQL์์ ์กฐํํ๋ ์ฃผ์ฒด๊ฐ ๋๋ Entity๋ง ์กฐํํ์ฌ ์์ํ.
- ์กฐํ์ ์ฃผ์ฒด๊ฐ ๋๋ Entity๋ง SELECTํด์ ์์ํํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ๋ ํ์ํ์ง ์์ง๋ง ์ฐ๊ด Entity๊ฐ ๊ฒ์์กฐ๊ฑด์๋ ํ์ํ ๊ฒฝ์ฐ์ ์ฃผ๋ก ์ฌ์ฉ๋๋ค.
# Fetch Join
- ์กฐํ์ ์ฃผ์ฒด๊ฐ ๋๋ Entity ์ด์ธ์ Fetch Join์ด ๊ฑธ๋ฆฐ ์ฐ๊ด Entity๋ ํจ๊ป SELECTํ์ฌ ๋ชจ๋ ์์ํ.
- Fetch Join์ด ๊ฑธ๋ฆฐ Entity ๋ชจ๋ ์์ํํ๊ธฐ ๋๋ฌธ์ FetchType์ด Lazy์ธ Entity๋ฅผ ์ฐธ์กฐํ๋๋ผ๋ ์ด๋ฏธ ์์์ฑ ์ปจํ ์คํธ์ ๋ค์ด์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ์ฟผ๋ฆฌ๊ฐ ์คํ๋์ง ์์ ์ฑ๋ก N+1๋ฌธ์ ๊ฐ ํด๊ฒฐ๋๋ค.
# 0503 - OAtuh๊ด๋ จ
OAuth๋ ์ธํฐ๋ท ์ฌ์ฉ์๋ค์ด ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๊ณตํ์ง ์๊ณ ๋ค๋ฅธ ์น์ฌ์ดํธ ์์ ์์ ๋ค์ ์ ๋ณด์ ๋ํด ์น์ฌ์ดํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๊ทผ ๊ถํ์ ๋ถ์ฌ ํ ์ ์๋ ๊ณตํต์ ์ธ ์๋จ์ผ๋ก์ ์ฌ์ฉ๋๋, ์ ๊ทผ ์์์ ์ํ ๊ฐ๋ฐฉํ ํ์ค์ด๋ค. ์ฝ๊ฒ๋งํด, ์์ ์ด ์์ ํ ๋ฆฌ์์ค์ ์ํํธ์จ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ๊ทผํ ์ ์๋๋ก ํ์ฉํด ์ค์ผ๋ก์จ ์ ๊ทผ ๊ถํ์ ์์ํด์ฃผ๋ ๊ฐ๋ฐฉํ ํ์ค ํ๋กํ ์ฝ
์ฉ์ด
- Resource Server : OAuth2.0 ์๋น์ค๋ฅผ ์ ๊ณตํ๊ณ ์์์ ๊ด๋ฆฌํ๋ ์๋ฒ
- Resource Owner : Resource Server์ ๊ณ์ ์ ์์ ํ๊ณ ์๋ ์ฌ์ฉ์
- Client : Resource Server์ API๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ค๊ณ ํ๋ ์ฌ์ดํธ
- Authorization Server : Client๊ฐ Resource Server์ ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ์ธ์ฆํ๊ณ ํ ํฐ์ ๋ฐ์ํด์ฃผ๋ ์๋ฒ
- Access Token : ์์ ์๋ฒ์ ์์์ ์์ฒญํ ์ ์๋ ํ ํฐ
- Refresh Token : ๊ถํ ์๋ฒ์ ์ ๊ทผ ํ ํฐ์ ์์ฒญํ ์ ์๋ ํ ํฐ
OAuth Bearer token๊ณผ JWTํ ํฐ์ ์ฐจ์ด
OAuth Token์ ์ด๋ค ์ฌ์ฉ์์ ์ ๋ณด์ ๊ฐ์ ์ค์ํ ์ ๋ณด๊ฐ ์๋ ํ ํฐ์ ์๋๋ฉฐ, ๋ฆฌ๋ก์ค ์๋ฒ์์ ์ ๋ณด๋ฅผ ์์ฒญํ ์ฉ๋๋ก ์ฌ์ฉ. JWT๋ payload์ ๋ช ํํ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ํค๋, ๋ด์ฉ, ์๋ช ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
# 0504 - @GeneratedValue ์ ๋ต
๊ธฐ๋ณธํค๋ฅผ ์๋์ผ๋ก ์์ฑํ๊ธฐ ์ํด ์ฌ์ฉ
# IDENTITY
@GeneratedValue(strategy = GenerationType.IDENTITY)
- ๊ธฐ๋ณธํค ์์ฑ์ ๋ฐ์ดํฐ ๋ฒ ์ด์ค์๊ฒ ์์ํ๋ ๋ฐฉ์์ผ๋ก id๊ฐ์ ๋ฐ๋ก ํ ๋นํ์ง ์์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์๋์ผ๋ก AUTO_INCREMENT๋ฅผ ํ์ฌ ๊ธฐ๋ณธํค๋ฅผ ์์ฑํด์ค๋ค.
JPA๋ ๋ณดํต ์์์ฑ ์ปจํ ์คํธ์์ ๊ฐ์ฒด๋ฅผ ๊ด๋ฆฌํ๋ค๊ฐ commit์ด ํธ์ถ๋๋ ์์ ์ ์ฟผ๋ฆฌ๋ฌธ์ ์คํํ๊ฒ๋๋ค. ํ์ง๋ง IDENTITY ์ ๋ต์์๋ EntityManager.persist()๋ฅผ ํ๋ ์์ ์ Insert SQL์ ์คํํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์๋ณ์๋ฅผ ์กฐํํด์จ๋ค.
๊ทธ ์ด์ ๋ ์์์ฑ ์ปจํ ์คํธ๋ 1์ฐจ ์บ์์ PK์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ง๊ณ ๊ด๋ฆฌ๋ฅผ ํ๋๋ฐ ๊ธฐ๋ณธํค๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์๊ฒ ์์ํ๊ธฐ ๋๋ฌธ์ EntityManage.persist() ํธ์ถ ํ๋๋ผ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ์ ๋ฃ๊ธฐ์ ๊น์ง ๊ธฐ๋ณธํค๋ฅผ ๋ชจ๋ฅด๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ด๋ฆฌ๊ฐ ๋์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฐ๋ผ์ ํน๋ณํ ๊ฒฝ์ฐ๋ก IDENTITY ์ ๋ต์์๋ EntityManage.persist()๋ฅผ ํ๋ ์์ ์ Insert SQL์ ์คํํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์๋ณ์๋ฅผ ์กฐํํ์ฌ ์์์ฑ ์ปจํ ์คํธ 1์ฐจ ์บ์์ ๊ฐ์ ๋ฃ์ด์ฃผ๊ธฐ ๋๋ฌธ์ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ง๋ค.
# SEQUENCE
@Entity
@SequenceGenerator(
name = "USER_PK_GENERATOR",
sequenceName = "USER_PK_SEQ",
initailValue = 1,
allocationSize = 50
)
public class PkEx() {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="USER_PK_GENERATOR")
private Long id;
private String name;
}
- ๋ฐ์ดํฐ ๋ฒ ์ด์ค์ Sequence Object๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์๋์ผ๋ก ๊ธฐ๋ณธํค๋ฅผ ์์ฑํด์ค๋ค.
- @SequenceGenerator ์ด๋ ธํ ์ด์ ์ด ํ์ํ๋ค.
SEQUENCE ์ ๋ต๋ IDENTITY ์ ๋ต๊ณผ ๋์ผํ ๋ฌธ์ ๊ฐ ์๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ง์ ๊ธฐ๋ณธํค๋ฅผ ์์ฑํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
ENtityManage.persist() ๊ฐ ํธ์ถ ๋๊ธฐ ์ ์ ๊ธฐ๋ณธํค๋ฅผ ๊ฐ์ ธ์์ผ ํ๋ฏ๋ก ํ์ด๋ฒ๋ค์ดํธ์์ hibernamte:call next value for USER_PK_SEQ์ ์คํํ์ฌ ๊ธฐ๋ณธํค๋ฅผ ๊ฐ์ ธ์จ๋ค.
๊ทธ ํ์ EntityManager.persist() ํธ์ถํ๊ธฐ ๋๋ฌธ์ IDENTITY ์ ๋ต๊ณผ ๋ค๋ฅด๊ฒ ์ฟผ๋ฆฌ๋ฌธ์ ์คํํ์ง ์๋๋ค.
ํ์ง๋ง SEQUENCE ๊ฐ์ ๊ณ์ DB์์ ๊ฐ์ ธ์์ ์ฌ์ฉํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ์ ํ๋ฅผ ์ผ์ผํฌ ์ ์๋ค.
ํด๊ฒฐ๋ฐฉ๋ฒ์ allocationSize์ ํฌ๊ธฐ๋ฅผ ์ ๋นํ ์ค์ ํ์ฌ ์ฑ๋ฅ ์ ํ ๊ฐ์ ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
# TABLE
@Entity
@TableGenerator(
name = "USER_PK_GENERATOR",
table = "USER_PK_SEQ",
pkColumnValue = "USER_SEQ",
allocationSize = 1
)
public class PkEx() {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="USER_PK_GENERATOR")
private Long id;
private String name;
}
- ํค๋ฅผ ์์ฑํ๋ ํ ์ด๋ธ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ผ๋ก Sequence์ ์ ์ฌํ๋ค.
- @TableGenerator ์ด๋ ธํ ์ด์ ์ด ํ์ํ๋ค.
TABLE ์ ๋ต์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ์ง๋ง ์ต์ ํ ๋์ด์์ง ์์ ํ ์ด๋ธ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ์ด์๊ฐ ์๋ค.
# AUTO
@GeneratedValue(strategy = GenerationType.AUTO)
- ๊ธฐ๋ณธ ์ค์ ๊ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ๋ผ ๊ธฐ๋ณธํค๋ฅผ ์๋์ผ๋ก ์์ฑํ๋ค.
# ๊ธฐ๋ณธํค์ ์ ์ฝ์กฐ๊ฑด
- null์ด๋ฉด ์๋๋ค.
- ์ ์ผํ๊ฒ ์ค๋ฒฝํ ์ ์์ด์ผํ๋ค.
- ๋ณํ์ง ์๋ ๊ฐ์ด์ด์ผ ํ๋ค.
# 0508 - @Retryable
ํน์ Exception์ด ๋ฐ์ํ์ ๊ฒฝ์ฐ ์ผ์ ํ์๋งํผ ์ฌ์๋ํ ์ ์๋ ์ด๋ ธํ ์ด์ ์ด๋ค.
- dependencies ์ค์
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web:2.5.4'
implementation 'org.springframework.retry:spring-retry:1.3.1'
runtimeOnly 'org.aspectj:aspectjweaver:1.9.7'
- EnableRetry ์ค์
@SpringBootApplication
@EnableRetry
public class FailsafeRetryApplication {
public static void main(String[] args) {
SpringApplication.run(FailsafeRetryApplication.class, args);
}
}
- @Retryable๋ก ์ฌ์๋ ์งํ
@Service
public class RetryableService {
@Retryable(maxAttempts = 2, backoff = @Backoff(2000), value = IllegalStateException.class,
exclude = { NullPointerException.class, NullPointerException.class })
public String getRetryable(Integer intValue) {
...
}
@Recover
String recover(NullPointerException e) {
return e.getMessage();
}
@Recover
String recover(NumberFormatException e, Integer intValue) {
return String.format("%s : %s", e.getMessage(), intValue);
}
}
- value, include : retryํ Exception์ ์ง์ ํ๋ค.
- exclude : ์ ์ธํ Exception์ ์ง์ ํ๋ค.
- maxAttempts : ์ต๋ ์ฌ์๋ ํ์(default 3)
- backoff : ์ฌ์๋ pause ์๊ฐ
- @Recover์ ๊ฒฝ์ฐ ๋ฐ์ํ Exception์ ๋ํ return ์ฒ๋ฆฌ๋ฅผ ์งํํ ์ ์๋ค. ๋จ, ๋ฆฌํดํ์
์ @Retryable์ ์ ์ํ ๋ฆฌํดํ์
๊ณผ ๋์ผํด์ผ ํ๋ค.
# 0511 - isBlank, isEmpty, hasText
- ์๋ฐ 11๋ฒ์ String.isBlank() : "", null, whitespace ์ฒดํฌ
- isEmpty() : ", null ์ฒดํฌ (deprecated)
- StringUtils.hasText() : "", null, whitespace ์ฒดํฌ