From 1f77f4daa0db3dbd82077d7e46c2c2351cf6a9d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=A3=BC=ED=98=95?= Date: Wed, 15 Dec 2021 15:12:52 +0900 Subject: [PATCH 01/12] =?UTF-8?q?create:=20[Spring]=20=EB=8B=A4=EC=96=91?= =?UTF-8?q?=ED=95=9C=20=EC=9D=98=EC=A1=B4=EA=B4=80=EA=B3=84=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\354\236\205 \353\260\251\353\262\225.md" | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 "Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" diff --git "a/Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" "b/Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" new file mode 100644 index 0000000..85ea3e9 --- /dev/null +++ "b/Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" @@ -0,0 +1,104 @@ +# 의존성 주입 방법 +# 요약 + - [생성자 주입(권장) - 불변, 필수](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=1.%20%EC%83%9D%EC%84%B1%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Constructor%20Injection%29) + - [수정자 주입 - 선택, 변경](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=2.%20%EC%88%98%EC%A0%95%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Setter%20Injection%29) + - [필드 주입 - 테스트 용이](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=3.%20%ED%95%84%EB%93%9C%20%EC%A3%BC%EC%9E%85%28Field%20Injection%29) + +# 1. 생성자 주입(Constructor Injection) + - 생성자를 통해 의존 관계를 주입하는 방법 + - 생성자 호출시점에 딱 1번만 호출되는 것이 보장됨 + -> 객체 생성 시, 개발자가 설정한 그대로 의존 관계가 주입됨 + - 때문에 주입받은 객체가 ::변하지 않거나::, 반드시 객체의 주입이 ::필요한 경우::에 강제하기 위해 사용할 수 있다 -> **불변,** **필수**(강제) +``` +@Service +public class UserServiceImpl implements UserService { + private UserRepository userRepository; + + @Autowired + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } +} +``` + + - 생성자 1개만 있을 경우 @Autowired 생략해도 자동 주입 됨 +``` +@Service +public class UserServiceImpl implements UserService { + private UserRepository userRepository; + + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } +} +``` + +> Spring 프레임워크에서도 생성자 주입을 추천하고 있음(**Always**) +> `Spring Team recommends: "Always use constructor based dependency injection in your beans` + + +# 2. 수정자 주입(Setter Injection) + - 필드 값을 변경하는 수정자 메서드인 Setter를 사용해 의존 관계를 주입하는 방법 + - 주입받는 객체가 변경될 가능성이 있는 경우에 사용(사용해본적은 없는데, 필요한 경우도 드물다고 함..) + - 수정이 가능하기에 **선택**, **변경** 가능성이 있는 의존 관계에 사용 +``` +@Service +public class UserServiceImpl implements UserService { + private UserRepository userRepository; + + @Autowired + public setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } +} +``` + +> @Autowired의 기본 동작은 주입할 대상이 없으면 오류 발생. +> 주입할 대상이 없어도 동작하게 하려면 `@Autowired(required = false)`로 지정 + + +## . 필드 주입(Field Injection) + - 필드에 의존 관계를 바로 주입하는 방법 + - **단점**(사용하지 말자!) + - 외부에서 변경이 불가능 + - DI 프레임워크가 반드시 필요(순수 자바 테스트에서는 사용 불가능) + +``` +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository userRepository; +} +``` + +> 테스트 코드, 또는 @Configuration 같은 곳에서만 특별한 용도로 사용(실제 코드와 상관없으며, 간결하기 때문에) + +> 테스트 코드는 순수한 자바 테스트가 기본임으로 @Autowired 동작X +> `@SpringBootTest` 어노테이션으로 스프링 컨테이너를 테스트에 통합한 경우에만 가능 + + +# 4. 일반 메서드 주입(Method Injection) + - 일반 메서드를 통해서 주입하는 방법 + - 한번에 여러 필드를 주입할 수 있지만, 일반적으로 사용X + +``` +@Service +public class UserServiceImpl implements UserService { + + private UserRepository userRepository; + private AAAA aaaa; + + @Autowired + public void init(UserRepository userRepository, AAAA aaaa) { + this.userRepository = userRepository; + this.aaaa = aaaa; + } +} +``` + + + + +## 출처 +- [스프링 핵심 원리 - 기본편 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard) From 8876763a2347db89e576155715d9d9b1aad1c527 Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Wed, 15 Dec 2021 15:35:51 +0900 Subject: [PATCH 02/12] =?UTF-8?q?create:=20[Spring]=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=20=EC=A3=BC=EC=9E=85=EC=9D=84=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=B4=EC=95=BC=ED=95=98=EB=8A=94=20=EC=9D=B4=EC=9C=A0(#8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0\353\212\224 \354\235\264\354\234\240.md" | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 "Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" diff --git "a/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" "b/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" new file mode 100644 index 0000000..5ad3d5a --- /dev/null +++ "b/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" @@ -0,0 +1,150 @@ +# 생성자 주입을 사용해야하는 이유 +# 요약 +- [객체의 불변성 확보](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=1.%20%EA%B0%9D%EC%B2%B4%EC%9D%98%20%EB%B6%88%EB%B3%80%EC%84%B1%20%ED%99%95%EB%B3%B4) +- [테스트 코드 작성 용이](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=2.%20%ED%85%8C%EC%8A%A4%ED%8A%B8%20%EC%BD%94%EB%93%9C%EC%9D%98%20%EC%9E%91%EC%84%B1) +- [final키워드 작성으로 실수를 줄이고 Lombok과의 연계가 좋다](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=3.%20final%20%ED%82%A4%EC%9B%8C%EB%93%9C%20%EC%9E%91%EC%84%B1%20%EB%B0%8F%20Lombok%EA%B3%BC%EC%9D%98%20%EA%B2%B0%ED%95%A9) +- [순환 참조 에러를 사전에 방지한다](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=4.%20%EC%88%9C%ED%99%98%20%EC%B0%B8%EC%A1%B0%20%EC%97%90%EB%9F%AC%20%EB%B0%A9%EC%A7%80) + +# 1. 객체의 불변성 확보 + - 대부분 의존 관계 주입은 애플리케이션 종료시점까지 변하면 안됨! + - Setter를 열어두는 것은 좋은 설계 방법이 아님(누군가 실수로 변경할 수 있음) + -> OCP(Open/closed principle) 위배 + - 생성자 주입은 생성 시 딱 1번만 호출됨으로 불변하게 설계할 수 있음 + - final 키워드 설정 가능(불변임으로) + +# 2. 테스트 코드의 작성 +## 생성자 주입이 아닐 경우 + - 필드 주입을 사용한다면 테스트 환경은 실제 코드의 DI 프레임워크 위에서 동작하지 않고, 순수한 자바 코드로 동작 -> **Null Point Exception 에러 발생, 테스트 하는 것이 불가능** + +### 실제 코드 +``` +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository userRepository; + + public UserRepository getUserRepository() { + return userRepository; + } +} +``` + +### 테스트 코드 +``` +public class UserServiceTest { + @Test + public void injectionTest() { + UserService userSerivce = new UserServiceImpl(); + UserRepository ur = userService.getUserRepository(); + System.out.println(ur); + } +``` + +> DI 프레임워크가 없는 순수한 자바 코드 테스트임으로 의존 관계 주입이 누락되어 UserRepository가 null인 NPE발생 + + - 위의 문제를 해결하기 위해선 Setter를 사용하면 되지만**, 싱글톤 패턴을 해칠 수 있다.** 또한 수정자 주입과 다를 바가 없으면서 수정자 주입 역시 **OCP 위배**한다는 문제가 있음 + + +## 생성자 주입일 경우 + - 의존 관계 주입이 누락될 경우 **컴파일 오류**가 발생 + - 어떤 값을 필수로 주입해야하는 지 확실하게 알 수 있음! + +### 실제 코드 +``` +@Service +public class UserServiceImpl implements UserService { + + private UserRepository userRepository; + + @Autowired + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } + + public UserRepository getUserRepository() { + return userRepository; + } +} +``` + +### 테스트 코드 +``` +public class UserServiceTest { + @Test + public void injectionTest() { + UserService userSerivce = new UserServiceImpl(); + UserRepository ur = userService.getUserRepository(); + System.out.println(ur); + } +``` + +> 컴파일 오류 발생 : `java: constructor UserServiceImpl in class (패키지명).UserServiceImpl cannot be applied to given types; required: (패키지명).UserRepository` + + +# 3. final 키워드 작성 및 Lombok과의 결합 +## final 키워드 작성 + - 생성자 주입은 final 키워드 사용 가능 + -> 값 설정 누락 시 컴파일 시점에 오류 발생 + - 누락된 의존성 확인이 빠름! + +## Lombok과의 결합 + - `@RequiredArgsConstructor` + -> final이 붙은 필드(변수)를 모두 모아 생성자를 자동으로 생성 + - 필드 주입보다 더 간결한 코드! + +> **최종 코드** +``` +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; +} +``` + + +# 4. 순환 참조 에러 방지 + +## 필드 or 수정자 주입의 경우 + - 예시 (닭은 알을 낳고, 알은 닭으로 부화하고) +``` +@Component +public class Chicken { + @Autowired Egg egg; + + public void layEgg() { + egg.hatch(); + } +} +``` + +``` +@Component +public class Egg { + @Autowired Chicken chicken; + + public void hatch() { + chicken.layEgg; + } +} +``` + +> 두 메소드는 서로를 순환하며 호출하다가, 메모리에 CallStack이 쌓여 StackOverFlow 에러를 발생 + +## 생성자 주입의 경우 + - 애플리케이션 구동 시점(객체 생성 시점)에 컴파일 오류를 발생시켜 순환 참조 에러를 방지 + +``` +Description: The dependencies of some of the beans in the application context form a cycle: +┌─────┐ +| chicken defined in file [(경로)/Chicken.class] +↑ ↓ +| egg defined in file [(경로)\Egg.class] +└─────┘ +``` + +> 생성자 주입의 컴파일 에러가 오류 잡기 좋다.. + +## 출처 +- [스프링 핵심 원리 - 기본편 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard) \ No newline at end of file From b9133376a1b3600266faac0c9c8014cff6f30bc3 Mon Sep 17 00:00:00 2001 From: leeejuhyeong <83570399+leeejuhyeong@users.noreply.github.com> Date: Wed, 15 Dec 2021 15:50:18 +0900 Subject: [PATCH 03/12] =?UTF-8?q?Delete=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=A3=BC=EC=9E=85=20=EB=B0=A9=EB=B2=95.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\354\236\205 \353\260\251\353\262\225.md" | 104 ------------------ 1 file changed, 104 deletions(-) delete mode 100644 "Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" diff --git "a/Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" "b/Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" deleted file mode 100644 index 85ea3e9..0000000 --- "a/Spring/\354\235\230\354\241\264\354\204\261 \354\243\274\354\236\205 \353\260\251\353\262\225.md" +++ /dev/null @@ -1,104 +0,0 @@ -# 의존성 주입 방법 -# 요약 - - [생성자 주입(권장) - 불변, 필수](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=1.%20%EC%83%9D%EC%84%B1%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Constructor%20Injection%29) - - [수정자 주입 - 선택, 변경](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=2.%20%EC%88%98%EC%A0%95%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Setter%20Injection%29) - - [필드 주입 - 테스트 용이](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=3.%20%ED%95%84%EB%93%9C%20%EC%A3%BC%EC%9E%85%28Field%20Injection%29) - -# 1. 생성자 주입(Constructor Injection) - - 생성자를 통해 의존 관계를 주입하는 방법 - - 생성자 호출시점에 딱 1번만 호출되는 것이 보장됨 - -> 객체 생성 시, 개발자가 설정한 그대로 의존 관계가 주입됨 - - 때문에 주입받은 객체가 ::변하지 않거나::, 반드시 객체의 주입이 ::필요한 경우::에 강제하기 위해 사용할 수 있다 -> **불변,** **필수**(강제) -``` -@Service -public class UserServiceImpl implements UserService { - private UserRepository userRepository; - - @Autowired - public UserServiceImpl(UserRepository userRepository) { - this.userRepository = userRepository; - } -} -``` - - - 생성자 1개만 있을 경우 @Autowired 생략해도 자동 주입 됨 -``` -@Service -public class UserServiceImpl implements UserService { - private UserRepository userRepository; - - public UserServiceImpl(UserRepository userRepository) { - this.userRepository = userRepository; - } -} -``` - -> Spring 프레임워크에서도 생성자 주입을 추천하고 있음(**Always**) -> `Spring Team recommends: "Always use constructor based dependency injection in your beans` - - -# 2. 수정자 주입(Setter Injection) - - 필드 값을 변경하는 수정자 메서드인 Setter를 사용해 의존 관계를 주입하는 방법 - - 주입받는 객체가 변경될 가능성이 있는 경우에 사용(사용해본적은 없는데, 필요한 경우도 드물다고 함..) - - 수정이 가능하기에 **선택**, **변경** 가능성이 있는 의존 관계에 사용 -``` -@Service -public class UserServiceImpl implements UserService { - private UserRepository userRepository; - - @Autowired - public setUserRepository(UserRepository userRepository) { - this.userRepository = userRepository; - } -} -``` - -> @Autowired의 기본 동작은 주입할 대상이 없으면 오류 발생. -> 주입할 대상이 없어도 동작하게 하려면 `@Autowired(required = false)`로 지정 - - -## . 필드 주입(Field Injection) - - 필드에 의존 관계를 바로 주입하는 방법 - - **단점**(사용하지 말자!) - - 외부에서 변경이 불가능 - - DI 프레임워크가 반드시 필요(순수 자바 테스트에서는 사용 불가능) - -``` -@Service -public class UserServiceImpl implements UserService { - - @Autowired - private UserRepository userRepository; -} -``` - -> 테스트 코드, 또는 @Configuration 같은 곳에서만 특별한 용도로 사용(실제 코드와 상관없으며, 간결하기 때문에) - -> 테스트 코드는 순수한 자바 테스트가 기본임으로 @Autowired 동작X -> `@SpringBootTest` 어노테이션으로 스프링 컨테이너를 테스트에 통합한 경우에만 가능 - - -# 4. 일반 메서드 주입(Method Injection) - - 일반 메서드를 통해서 주입하는 방법 - - 한번에 여러 필드를 주입할 수 있지만, 일반적으로 사용X - -``` -@Service -public class UserServiceImpl implements UserService { - - private UserRepository userRepository; - private AAAA aaaa; - - @Autowired - public void init(UserRepository userRepository, AAAA aaaa) { - this.userRepository = userRepository; - this.aaaa = aaaa; - } -} -``` - - - - -## 출처 -- [스프링 핵심 원리 - 기본편 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard) From 3cb2f6e2b59234312114d9718565c54e9caa2989 Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Wed, 15 Dec 2021 15:53:08 +0900 Subject: [PATCH 04/12] =?UTF-8?q?create:=20[Spring]=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EA=B4=80=EA=B3=84=20=EC=A3=BC=EC=9E=85=20=EB=B0=A9=EB=B2=95(#6?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\354\236\205 \353\260\251\353\262\225.md" | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 "Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" diff --git "a/Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" "b/Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" new file mode 100644 index 0000000..85ea3e9 --- /dev/null +++ "b/Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" @@ -0,0 +1,104 @@ +# 의존성 주입 방법 +# 요약 + - [생성자 주입(권장) - 불변, 필수](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=1.%20%EC%83%9D%EC%84%B1%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Constructor%20Injection%29) + - [수정자 주입 - 선택, 변경](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=2.%20%EC%88%98%EC%A0%95%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Setter%20Injection%29) + - [필드 주입 - 테스트 용이](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=3.%20%ED%95%84%EB%93%9C%20%EC%A3%BC%EC%9E%85%28Field%20Injection%29) + +# 1. 생성자 주입(Constructor Injection) + - 생성자를 통해 의존 관계를 주입하는 방법 + - 생성자 호출시점에 딱 1번만 호출되는 것이 보장됨 + -> 객체 생성 시, 개발자가 설정한 그대로 의존 관계가 주입됨 + - 때문에 주입받은 객체가 ::변하지 않거나::, 반드시 객체의 주입이 ::필요한 경우::에 강제하기 위해 사용할 수 있다 -> **불변,** **필수**(강제) +``` +@Service +public class UserServiceImpl implements UserService { + private UserRepository userRepository; + + @Autowired + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } +} +``` + + - 생성자 1개만 있을 경우 @Autowired 생략해도 자동 주입 됨 +``` +@Service +public class UserServiceImpl implements UserService { + private UserRepository userRepository; + + public UserServiceImpl(UserRepository userRepository) { + this.userRepository = userRepository; + } +} +``` + +> Spring 프레임워크에서도 생성자 주입을 추천하고 있음(**Always**) +> `Spring Team recommends: "Always use constructor based dependency injection in your beans` + + +# 2. 수정자 주입(Setter Injection) + - 필드 값을 변경하는 수정자 메서드인 Setter를 사용해 의존 관계를 주입하는 방법 + - 주입받는 객체가 변경될 가능성이 있는 경우에 사용(사용해본적은 없는데, 필요한 경우도 드물다고 함..) + - 수정이 가능하기에 **선택**, **변경** 가능성이 있는 의존 관계에 사용 +``` +@Service +public class UserServiceImpl implements UserService { + private UserRepository userRepository; + + @Autowired + public setUserRepository(UserRepository userRepository) { + this.userRepository = userRepository; + } +} +``` + +> @Autowired의 기본 동작은 주입할 대상이 없으면 오류 발생. +> 주입할 대상이 없어도 동작하게 하려면 `@Autowired(required = false)`로 지정 + + +## . 필드 주입(Field Injection) + - 필드에 의존 관계를 바로 주입하는 방법 + - **단점**(사용하지 말자!) + - 외부에서 변경이 불가능 + - DI 프레임워크가 반드시 필요(순수 자바 테스트에서는 사용 불가능) + +``` +@Service +public class UserServiceImpl implements UserService { + + @Autowired + private UserRepository userRepository; +} +``` + +> 테스트 코드, 또는 @Configuration 같은 곳에서만 특별한 용도로 사용(실제 코드와 상관없으며, 간결하기 때문에) + +> 테스트 코드는 순수한 자바 테스트가 기본임으로 @Autowired 동작X +> `@SpringBootTest` 어노테이션으로 스프링 컨테이너를 테스트에 통합한 경우에만 가능 + + +# 4. 일반 메서드 주입(Method Injection) + - 일반 메서드를 통해서 주입하는 방법 + - 한번에 여러 필드를 주입할 수 있지만, 일반적으로 사용X + +``` +@Service +public class UserServiceImpl implements UserService { + + private UserRepository userRepository; + private AAAA aaaa; + + @Autowired + public void init(UserRepository userRepository, AAAA aaaa) { + this.userRepository = userRepository; + this.aaaa = aaaa; + } +} +``` + + + + +## 출처 +- [스프링 핵심 원리 - 기본편 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard) From 54e279288d13e1f46602526105caf82a74e69af2 Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Tue, 21 Dec 2021 18:00:13 +0900 Subject: [PATCH 05/12] =?UTF-8?q?docs:=20=EC=9D=98=EC=A1=B4=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20=EC=A3=BC=EC=9E=85=20=EB=B0=A9=EB=B2=95.md=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0\353\212\224 \354\235\264\354\234\240.md" | 10 +++--- ...4\354\236\205 \353\260\251\353\262\225.md" | 32 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git "a/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" "b/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" index 5ad3d5a..12e382a 100644 --- "a/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" +++ "b/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" @@ -41,7 +41,7 @@ public class UserServiceTest { } ``` -> DI 프레임워크가 없는 순수한 자바 코드 테스트임으로 의존 관계 주입이 누락되어 UserRepository가 null인 NPE발생 +> DI 프레임워크가 없는 순수한 자바 코드 테스트임으로 의존 관계 주입이 누락되어 UserRepository가 null인 NPE발생 - 위의 문제를 해결하기 위해선 Setter를 사용하면 되지만**, 싱글톤 패턴을 해칠 수 있다.** 또한 수정자 주입과 다를 바가 없으면서 수정자 주입 역시 **OCP 위배**한다는 문제가 있음 @@ -79,7 +79,7 @@ public class UserServiceTest { } ``` -> 컴파일 오류 발생 : `java: constructor UserServiceImpl in class (패키지명).UserServiceImpl cannot be applied to given types; required: (패키지명).UserRepository` +> 컴파일 오류 발생 : `java: constructor UserServiceImpl in class (패키지명).UserServiceImpl cannot be applied to given types; required: (패키지명).UserRepository` # 3. final 키워드 작성 및 Lombok과의 결합 @@ -93,7 +93,7 @@ public class UserServiceTest { -> final이 붙은 필드(변수)를 모두 모아 생성자를 자동으로 생성 - 필드 주입보다 더 간결한 코드! -> **최종 코드** +> **최종 코드** ``` @Service @RequiredArgsConstructor @@ -130,7 +130,7 @@ public class Egg { } ``` -> 두 메소드는 서로를 순환하며 호출하다가, 메모리에 CallStack이 쌓여 StackOverFlow 에러를 발생 +> 두 메소드는 서로를 순환하며 호출하다가, 메모리에 CallStack이 쌓여 StackOverFlow 에러를 발생 ## 생성자 주입의 경우 - 애플리케이션 구동 시점(객체 생성 시점)에 컴파일 오류를 발생시켜 순환 참조 에러를 방지 @@ -144,7 +144,7 @@ Description: The dependencies of some of the beans in the application context fo └─────┘ ``` -> 생성자 주입의 컴파일 에러가 오류 잡기 좋다.. +> 생성자 주입의 컴파일 에러가 오류 잡기 좋다.. ## 출처 - [스프링 핵심 원리 - 기본편 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard) \ No newline at end of file diff --git "a/Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" "b/Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" index 85ea3e9..964c654 100644 --- "a/Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" +++ "b/Spring/\354\235\230\354\241\264\352\264\200\352\263\204 \354\243\274\354\236\205 \353\260\251\353\262\225.md" @@ -2,13 +2,13 @@ # 요약 - [생성자 주입(권장) - 불변, 필수](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=1.%20%EC%83%9D%EC%84%B1%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Constructor%20Injection%29) - [수정자 주입 - 선택, 변경](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=2.%20%EC%88%98%EC%A0%95%EC%9E%90%20%EC%A3%BC%EC%9E%85%28Setter%20Injection%29) - - [필드 주입 - 테스트 용이](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=3.%20%ED%95%84%EB%93%9C%20%EC%A3%BC%EC%9E%85%28Field%20Injection%29) + - [필드 주입 - 테스트용](bear://x-callback-url/open-note?id=8C4454B9-D369-4539-8BF5-47A2A4E8D2A7-2996-000020E440BDD277&header=3.%20%ED%95%84%EB%93%9C%20%EC%A3%BC%EC%9E%85%28Field%20Injection%29) # 1. 생성자 주입(Constructor Injection) - - 생성자를 통해 의존 관계를 주입하는 방법 - - 생성자 호출시점에 딱 1번만 호출되는 것이 보장됨 - -> 객체 생성 시, 개발자가 설정한 그대로 의존 관계가 주입됨 - - 때문에 주입받은 객체가 ::변하지 않거나::, 반드시 객체의 주입이 ::필요한 경우::에 강제하기 위해 사용할 수 있다 -> **불변,** **필수**(강제) +- 생성자를 통해 의존 관계를 주입하는 방법 +- 생성자 호출시점에 딱 1번만 호출되는 것이 보장됨 +-> 객체 생성 시, 개발자가 설정한 그대로 의존 관계가 주입됨 +- 때문에 주입받은 객체가 ::변하지 않거나::, 반드시 객체의 주입이 ::필요한 경우::에 강제하기 위해 사용할 수 있다 -> **불변,** **필수**(강제) ``` @Service public class UserServiceImpl implements UserService { @@ -21,7 +21,7 @@ public class UserServiceImpl implements UserService { } ``` - - 생성자 1개만 있을 경우 @Autowired 생략해도 자동 주입 됨 +- 생성자 1개만 있을 경우 @Autowired 생략해도 자동 주입 됨 ``` @Service public class UserServiceImpl implements UserService { @@ -38,9 +38,9 @@ public class UserServiceImpl implements UserService { # 2. 수정자 주입(Setter Injection) - - 필드 값을 변경하는 수정자 메서드인 Setter를 사용해 의존 관계를 주입하는 방법 - - 주입받는 객체가 변경될 가능성이 있는 경우에 사용(사용해본적은 없는데, 필요한 경우도 드물다고 함..) - - 수정이 가능하기에 **선택**, **변경** 가능성이 있는 의존 관계에 사용 +- 필드 값을 변경하는 수정자 메서드인 Setter를 사용해 의존 관계를 주입하는 방법 +- 주입받는 객체가 변경될 가능성이 있는 경우에 사용(사용해본적은 없는데, 필요한 경우도 드물다고 함..) +- 수정이 가능하기에 **선택**, **변경** 가능성이 있는 의존 관계에 사용 ``` @Service public class UserServiceImpl implements UserService { @@ -57,11 +57,11 @@ public class UserServiceImpl implements UserService { > 주입할 대상이 없어도 동작하게 하려면 `@Autowired(required = false)`로 지정 -## . 필드 주입(Field Injection) - - 필드에 의존 관계를 바로 주입하는 방법 - - **단점**(사용하지 말자!) - - 외부에서 변경이 불가능 - - DI 프레임워크가 반드시 필요(순수 자바 테스트에서는 사용 불가능) +# 3. 필드 주입(Field Injection) +- 필드에 의존 관계를 바로 주입하는 방법 +- **단점**(사용하지 말자!) + - 외부에서 변경이 불가능 + - DI 프레임워크가 반드시 필요(순수 자바 테스트에서는 사용 불가능) ``` @Service @@ -79,8 +79,8 @@ public class UserServiceImpl implements UserService { # 4. 일반 메서드 주입(Method Injection) - - 일반 메서드를 통해서 주입하는 방법 - - 한번에 여러 필드를 주입할 수 있지만, 일반적으로 사용X +- 일반 메서드를 통해서 주입하는 방법 +- 한번에 여러 필드를 주입할 수 있지만, 일반적으로 사용X ``` @Service From 8c1aca7009bc2eb472fddff2cf16b459b7bc0e52 Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Tue, 21 Dec 2021 18:05:54 +0900 Subject: [PATCH 06/12] =?UTF-8?q?docs:=20=EC=9D=98=EC=A1=B4=EA=B4=80?= =?UTF-8?q?=EA=B3=84=20=EC=A3=BC=EC=9E=85=20=EB=B0=A9=EB=B2=95.md=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Spring/.DS_Store | Bin 0 -> 6148 bytes ...\274\354\236\205 \353\260\251\353\262\225.md" | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 Spring/.DS_Store diff --git a/Spring/.DS_Store b/Spring/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Tue, 21 Dec 2021 18:13:38 +0900 Subject: [PATCH 07/12] =?UTF-8?q?docs:=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=A3=BC=EC=9E=85=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=B4?= =?UTF-8?q?=EC=95=BC=ED=95=98=EB=8A=94=20=EC=9D=B4=EC=9C=A0.md=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20#8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0\353\212\224 \354\235\264\354\234\240.md" | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git "a/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" "b/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" index 12e382a..ed7a1ca 100644 --- "a/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" +++ "b/Spring/\354\203\235\354\204\261\354\236\220 \354\243\274\354\236\205\354\235\204 \354\202\254\354\232\251\355\225\264\354\225\274\355\225\230\353\212\224 \354\235\264\354\234\240.md" @@ -5,16 +5,18 @@ - [final키워드 작성으로 실수를 줄이고 Lombok과의 연계가 좋다](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=3.%20final%20%ED%82%A4%EC%9B%8C%EB%93%9C%20%EC%9E%91%EC%84%B1%20%EB%B0%8F%20Lombok%EA%B3%BC%EC%9D%98%20%EA%B2%B0%ED%95%A9) - [순환 참조 에러를 사전에 방지한다](bear://x-callback-url/open-note?id=B5467B00-E1D6-4C5B-8FA4-83B1A3B2975E-1500-00000B9786F1BC1D&header=4.%20%EC%88%9C%ED%99%98%20%EC%B0%B8%EC%A1%B0%20%EC%97%90%EB%9F%AC%20%EB%B0%A9%EC%A7%80) + # 1. 객체의 불변성 확보 - - 대부분 의존 관계 주입은 애플리케이션 종료시점까지 변하면 안됨! - - Setter를 열어두는 것은 좋은 설계 방법이 아님(누군가 실수로 변경할 수 있음) - -> OCP(Open/closed principle) 위배 - - 생성자 주입은 생성 시 딱 1번만 호출됨으로 불변하게 설계할 수 있음 - - final 키워드 설정 가능(불변임으로) +- 대부분 의존 관계 주입은 애플리케이션 종료시점까지 변하면 안됨! +- Setter를 열어두는 것은 좋은 설계 방법이 아님(누군가 실수로 변경할 수 있음) +-> OCP(Open/closed principle) 위배 +- 생성자 주입은 생성 시 딱 1번만 호출됨으로 불변하게 설계할 수 있음 +- final 키워드 설정 가능(불변임으로) + # 2. 테스트 코드의 작성 ## 생성자 주입이 아닐 경우 - - 필드 주입을 사용한다면 테스트 환경은 실제 코드의 DI 프레임워크 위에서 동작하지 않고, 순수한 자바 코드로 동작 -> **Null Point Exception 에러 발생, 테스트 하는 것이 불가능** +- 필드 주입을 사용한다면 테스트 환경은 실제 코드의 DI 프레임워크 위에서 동작하지 않고, 순수한 자바 코드로 동작 -> **Null Point Exception 에러 발생, 테스트 하는 것이 불가능** ### 실제 코드 ``` @@ -41,14 +43,16 @@ public class UserServiceTest { } ``` -> DI 프레임워크가 없는 순수한 자바 코드 테스트임으로 의존 관계 주입이 누락되어 UserRepository가 null인 NPE발생 +> DI 프레임워크가 없는 순수한 자바 코드 테스트임으로 의존 관계 주입이 누락되어 UserRepository가 null인 NPE발생 - - 위의 문제를 해결하기 위해선 Setter를 사용하면 되지만**, 싱글톤 패턴을 해칠 수 있다.** 또한 수정자 주입과 다를 바가 없으면서 수정자 주입 역시 **OCP 위배**한다는 문제가 있음 +- 위의 문제를 해결하기 위해선 Setter를 사용하면 되지만**, 싱글톤 패턴을 해칠 수 있다.** 또한 수정자 주입과 다를 바가 없으면서 수정자 주입 역시 **OCP 위배**한다는 문제가 있음 + +> OCP(Open/closed principle) : 개방-폐쇄 원칙, 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다. ## 생성자 주입일 경우 - - 의존 관계 주입이 누락될 경우 **컴파일 오류**가 발생 - - 어떤 값을 필수로 주입해야하는 지 확실하게 알 수 있음! +- 의존 관계 주입이 누락될 경우 **컴파일 오류**가 발생 +- 어떤 값을 필수로 주입해야하는 지 확실하게 알 수 있음! ### 실제 코드 ``` @@ -79,21 +83,21 @@ public class UserServiceTest { } ``` -> 컴파일 오류 발생 : `java: constructor UserServiceImpl in class (패키지명).UserServiceImpl cannot be applied to given types; required: (패키지명).UserRepository` +> 컴파일 오류 발생 : `java: constructor UserServiceImpl in class (패키지명).UserServiceImpl cannot be applied to given types; required: (패키지명).UserRepository` # 3. final 키워드 작성 및 Lombok과의 결합 ## final 키워드 작성 - - 생성자 주입은 final 키워드 사용 가능 - -> 값 설정 누락 시 컴파일 시점에 오류 발생 - - 누락된 의존성 확인이 빠름! +- 생성자 주입은 final 키워드 사용 가능 +-> 값 설정 누락 시 컴파일 시점에 오류 발생 +- 누락된 의존성 확인이 빠름! ## Lombok과의 결합 - - `@RequiredArgsConstructor` - -> final이 붙은 필드(변수)를 모두 모아 생성자를 자동으로 생성 - - 필드 주입보다 더 간결한 코드! +- `@RequiredArgsConstructor` +-> final이 붙은 필드(변수)를 모두 모아 생성자를 자동으로 생성 +- 필드 주입보다 더 간결한 코드! -> **최종 코드** +> **최종 코드** ``` @Service @RequiredArgsConstructor @@ -105,9 +109,8 @@ public class UserServiceImpl implements UserService { # 4. 순환 참조 에러 방지 - ## 필드 or 수정자 주입의 경우 - - 예시 (닭은 알을 낳고, 알은 닭으로 부화하고) +- 예시 (닭은 알을 낳고, 알은 닭으로 부화하고) ``` @Component public class Chicken { @@ -130,10 +133,10 @@ public class Egg { } ``` -> 두 메소드는 서로를 순환하며 호출하다가, 메모리에 CallStack이 쌓여 StackOverFlow 에러를 발생 +> 두 메소드는 서로를 순환하며 호출하다가, 메모리에 CallStack이 쌓여 StackOverFlow 에러를 발생 ## 생성자 주입의 경우 - - 애플리케이션 구동 시점(객체 생성 시점)에 컴파일 오류를 발생시켜 순환 참조 에러를 방지 +- 애플리케이션 구동 시점(객체 생성 시점)에 컴파일 오류를 발생시켜 순환 참조 에러를 방지 ``` Description: The dependencies of some of the beans in the application context form a cycle: @@ -144,7 +147,7 @@ Description: The dependencies of some of the beans in the application context fo └─────┘ ``` -> 생성자 주입의 컴파일 에러가 오류 잡기 좋다.. +> 생성자 주입의 컴파일 에러가 오류 잡기 좋다.. ## 출처 - [스프링 핵심 원리 - 기본편 - 인프런 | 강의](https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard) \ No newline at end of file From 50dd7b73d1ccbbf91fae608a666b73f672ca3f00 Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Thu, 23 Dec 2021 18:52:23 +0900 Subject: [PATCH 08/12] =?UTF-8?q?create:=20[Database]=20=EC=9D=B8=EB=8D=B1?= =?UTF-8?q?=EC=8A=A4=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=9D=B4=EC=9C=A0=20#12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...(\354\236\245\353\213\250\354\240\220).md" | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 "Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" diff --git "a/Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" "b/Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" new file mode 100644 index 0000000..852ee47 --- /dev/null +++ "b/Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" @@ -0,0 +1,82 @@ +# 인덱스를 사용하는 이유(장단점) +## 요약 +> 인덱스는 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조입니다. +> 사용 시 테이블 조회 속도를 높여 DB 성능을 향상시키며, Full Scan하지 않아 시스템 부하를 줄여줍니다. +> 하지만 항상 정렬된 상태로 유지해야하기에 추가적인 쓰기작업이 필요하며 이를 저장하기 위한 저장공간이 필요합니다. 때문에 잘못 사용할 경우 성능 저하의 역효과를 발생시킵니다. + + +## 인덱스(Index)란? +- 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조. +- 추가적인 쓰기 작업과 저장공간을 활용 +-> 이를 관리하기 위해 DB에 ~~약 10%에 해당하는~~ 저장공간 필요 +- **PK는 자동으로 Index가 생성됨** -> NHN 기출 +![인덱스 구조](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/index_structure.png?raw=true) + +> 인덱스 없이 조회하면 모든 튜플(레코드)를 검색하지만 인덱스를 사용한다면 인덱스를 탐색하고 일치할 시에 해당 튜플로 데이터를 검색. -> 속도 **up** + + +## 인덱스 관리 + - Index를 항상 **최신의 데이터를 정렬된 상태로 유지**해야 원하는 값을 탐색 할 수 있음 + - INSERT, UPDATE, DELETE(데이터 추가, 수정, 삭제) 수행 시 정렬 필요! -> 부하**UP** + - INSERT, UPDATE, DELETE 시 추가적인 연산 필요 + -> 부하를 최소화하기 위해 데이터 삭제라는 개념에서 인덱스를 사용하지 않는다 라는 작업으로 대신함 + - INSERT : 새로운 데이터에 대한 인덱스 추가 + - DELETE : 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업 진행 + - UPDATE : 기존의 인덱스를 사용하지 않음 처리, 갱신된 데이터에 대한 인덱스 추가 + + +## 인덱스의 장단점 +### 장점 +- 테이블을 조회하는 속도와 그에 따른 성능을 향상 +- 전반적인 시스템의 부하를 줄임(Full Scan을 안해서) + +### 단점 +- 인덱스를 관리하기 위해 DB의 ~~약 10%에 해당하는~~ 추가적인 저장공간 필요 +- 인덱스를 관리하기 위해 추가 작업 필요 +- 잘못 사용할 경우 성능 저하의 역효과 발생 + + +## 인덱스를 사용하는 이유 +### 조건 검색 Where 절의 효율성 +- 인덱스 테이블은 데이터들이 정렬되어 저장되어 있기 때문에 해당 조건(where)에 맞는 데이터를 빠르게 찾아낼 수 있음 + +### 정렬 Order by 절의 효율성 +- 이미 정렬되어 있기 떄문에 order by에 의한 Sort과정을 피할 수 있음 + +### MIN, MAX의 효율적인 처리 가능 +- MIN값과 MAX값을 레코드의 시작값과 끝 값 한 건씩만 가져오면 되기에 Full Scan보다 효율적 + + +## 인덱스 자료구조 +### 해시테이블 +- key : 데이터(= 컬럼의 값) +- value : 데이터의 위치 +- 장점 + - 빠른 데이터 탐색에 유용 + - 시간 복잡도 O(1) +- 단점 + - 등호 연산에만 특화 + - DB는 부등호(>, <) 연산이 많아서 **사용 부적합** +![인덱싱_해쉬](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/indexing_hash.png?raw=true) + +## B+ Tree +- 대부분의 DB 인덱싱 자료구조 +- 특징 + - 리프노드에만 인덱스와 함께 데이터를 갖고있고, 나머지 노드들은 인덱스만을 가짐 + - 리프노드들은 연결리스트로 이루어짐 -> 탐색이 0번노드부터 일어나는 연결리스트에 비해 시간 효율이 좋음!(log2(N)) + - 데이터 노드의 크기는 인덱스 노드와의 크기와 같지 않아도 됨 +- 예시 + - 인덱스 +![인덱싱_B+Tree1](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/indexing_b%2Btree1.jpeg?raw=true) + + - B+ Tree +![인덱싱_B+Tree2](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/indexing_b%2Btree2.jpeg?raw=true) + +> BTree : 모든 노드에 데이터를 담음 +> 리프노드 : 자식이 없는 노드. 잎이라고도 함 +> B+ Tree 알고리즘에 대해서는 추후 정리할 예정입니다. + + +- 출처 + - [Database 인덱스(index)란? - MangKyu’s Diary](https://mangkyu.tistory.com/96) + - [자료구조 그림으로 알아보는 B+Tree](https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Plus-Tree) \ No newline at end of file From 099bccdae27c3d9e870cf6ac90b3885939394f5f Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Sun, 26 Dec 2021 15:39:43 +0900 Subject: [PATCH 09/12] =?UTF-8?q?update=20:=20[Database]=20=EC=9D=B8?= =?UTF-8?q?=EB=8D=B1=EC=8A=A4=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=9D=B4=EC=9C=A0=20#12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...(\354\236\245\353\213\250\354\240\220).md" | 72 ++++++++++++++----- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git "a/Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" "b/Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" index 852ee47..a970245 100644 --- "a/Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" +++ "b/Database/\354\235\270\353\215\261\354\212\244\353\245\274 \354\202\254\354\232\251\355\225\230\353\212\224 \354\235\264\354\234\240(\354\236\245\353\213\250\354\240\220).md" @@ -15,14 +15,17 @@ > 인덱스 없이 조회하면 모든 튜플(레코드)를 검색하지만 인덱스를 사용한다면 인덱스를 탐색하고 일치할 시에 해당 튜플로 데이터를 검색. -> 속도 **up** -## 인덱스 관리 - - Index를 항상 **최신의 데이터를 정렬된 상태로 유지**해야 원하는 값을 탐색 할 수 있음 - - INSERT, UPDATE, DELETE(데이터 추가, 수정, 삭제) 수행 시 정렬 필요! -> 부하**UP** - - INSERT, UPDATE, DELETE 시 추가적인 연산 필요 - -> 부하를 최소화하기 위해 데이터 삭제라는 개념에서 인덱스를 사용하지 않는다 라는 작업으로 대신함 - - INSERT : 새로운 데이터에 대한 인덱스 추가 - - DELETE : 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업 진행 - - UPDATE : 기존의 인덱스를 사용하지 않음 처리, 갱신된 데이터에 대한 인덱스 추가 +## 인덱스를 사용하는 이유 +- 인덱스 테이블은 데이터들이 정렬되어 있음! -> **정렬과 연관지어 기억하자** + +### 조건 검색 Where 절의 효율성 +- 인덱스 테이블은 데이터들이 정렬되어 저장되어 있기 때문에 해당 조건(where)에 맞는 데이터를 빠르게 찾아낼 수 있음 + +### 정렬 Order by 절의 효율성 +- 이미 정렬되어 있기 떄문에 order by에 의한 Sort과정을 피할 수 있음 + +### MIN, MAX의 효율적인 처리 가능 +- MIN값과 MAX값을 레코드의 시작값과 끝 값 한 건씩만 가져오면 되기에 Full Scan보다 효율적 ## 인덱스의 장단점 @@ -36,15 +39,21 @@ - 잘못 사용할 경우 성능 저하의 역효과 발생 -## 인덱스를 사용하는 이유 -### 조건 검색 Where 절의 효율성 -- 인덱스 테이블은 데이터들이 정렬되어 저장되어 있기 때문에 해당 조건(where)에 맞는 데이터를 빠르게 찾아낼 수 있음 - -### 정렬 Order by 절의 효율성 -- 이미 정렬되어 있기 떄문에 order by에 의한 Sort과정을 피할 수 있음 - -### MIN, MAX의 효율적인 처리 가능 -- MIN값과 MAX값을 레코드의 시작값과 끝 값 한 건씩만 가져오면 되기에 Full Scan보다 효율적 +## 인덱스 관리 + - Index를 항상 **최신의 데이터를 정렬된 상태로 유지**해야 원하는 값을 탐색 할 수 있음 + - INSERT, UPDATE, DELETE(데이터 추가, 수정, 삭제) 수행 시 정렬 필요! -> 부하**UP** + - INSERT, UPDATE, DELETE 시 추가적인 연산 필요 + -> 부하를 최소화하기 위해 데이터 삭제라는 개념에서 **인덱스를 사용하지 않는다** 라는 작업으로 대신함 + - INSERT : 새로운 데이터에 대한 인덱스 추가 + - DELETE : 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업 진행 + - UPDATE : 기존의 인덱스를 사용하지 않음 처리, 갱신된 데이터에 대한 인덱스 추가 + + +## 인덱스 생성 전략 +- 조건절에 자주 등장하는 컬럼(호출 빈도가 높음) +- 같거나 크고, 작음으로 자주 사용되는 컬럼(where 또는 order by에서 쓰이는 컬럼) +- 중복되는 데이터가 최소한인 컬럼(분포도가 좋다 = 데이터가 서로 다르고 넓게 퍼져 있다) +- 조인 조건으로 자주 사용되는 컬럼 ## 인덱스 자료구조 @@ -77,6 +86,35 @@ > B+ Tree 알고리즘에 대해서는 추후 정리할 예정입니다. + +## TMI : 결합 인덱스 +- 두 개 이상의 컬럼을 합쳐서 인덱스를 만드는 것 +- 단일 컬럼으로는 분포도가 나쁘지만, 여러 개의 컬럼을 합친다면 좋은 분포도를 가지며, where절에서 and 조건에 많이 사용되는 컬럼을 결합 인덱스로 생성함 + +### 결합 인덱스 컬럼 생성 전략 +- where절에서 and 조건으로 자주 결합되고, 결합할 시 분포도가 좋아지는 컬럼 +- 다른 테이블과 조인의 연결고리로 자주 사용되는 컬럼 +- order by에서 자주 사용되는 컬럼 +- 하나 이상의 키 컬럼 조건으로 같은 테이블의 컬럼들이 자주 조회될 때 + +### 예시 +- 결합 인덱스 생성 예시 +`create index emp_pay_idx on emp_pay(급여년월, 급여코드, 사원번호);` +- 결합 인덱스 사용 예시 +``` +select * from emp_pay where 급여년월 = '202107'; +select * from emp_pay where 급여년월 = '202107' and 급여코드 = '정기급여'; +select * from emp_pay where 급여년월 = '202107' and 급여코드 = '정기급여' and 사원번호 = '20210401'; +``` + +> 단 급여코드만을 검색할 때는 결합 인덱스의 첫 번째 컬럼인 급여년월의 조건식이 없기 때문에 결합 인덱스로 조회하지 않음! -> 급여년월, 급여코드, 사원번호의 순서대로 조회 + - 결합 인덱스 효율성 감소 + 1. LIKE 검색 : 2021%같이 검색할 경우 2021에 해당하는 모든 급여코드, 정기급여로 생성된 결합 인덱스를 조회해서 B*Tree에서 조회하기 어려움 + 2. 결합 인덱스 칼럼 순서(이하 급여년월(1), 급여코드(2), 사원번호(3) 컬럼을 숫자로 말하겠습니다) + - 1, 3 / 2 / 2, 3 / 3 으로 조회할 경우 결합 인덱스 순서대로 조회하지 않아서 Full Scan이 발생합니다 + + - 출처 - [Database 인덱스(index)란? - MangKyu’s Diary](https://mangkyu.tistory.com/96) + - [DB 데이터베이스 인덱스(Index) 란 무엇인가?](https://coding-factory.tistory.com/746) - [자료구조 그림으로 알아보는 B+Tree](https://velog.io/@emplam27/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EA%B7%B8%EB%A6%BC%EC%9C%BC%EB%A1%9C-%EC%95%8C%EC%95%84%EB%B3%B4%EB%8A%94-B-Plus-Tree) \ No newline at end of file From dff2f8274b1ee81c733ab447d443a880a63fc2b2 Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Sun, 16 Jan 2022 13:56:37 +0900 Subject: [PATCH 10/12] create: [Database] Isolation Level #34 --- ...51\353\246\254\354\210\230\354\244\200.md" | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 "Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" diff --git "a/Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" "b/Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" new file mode 100644 index 0000000..caf9cf0 --- /dev/null +++ "b/Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" @@ -0,0 +1,96 @@ +# 트랜잭션 +## 목차 +### 1. 트랜잭션 정의 +## 2. Isolation Level +### 3. 동시성 제어(락 메커니즘) +### 4. 교착상태(Dead Lock)와 회복(Recovery) + + +# Isolation Level +## 요약 +- 격리 수준 혹은 고립 수준이라고 함 +- 동시에 여러 트랜잭션이 처리될 때, 트랜잭션끼리 얼마나 서로 고립되어있는지를 나타내는 것 +- READ UNCOMMITTED, READ COMMITED, REPEATABLE READ, SERIALIZABLE 4가지가 있음 +- 각 격리 수준에 따라 Dirty READ, NON-REPETABLE READ, Phantom Read가 발생 + +## Isolation Level이란(격리 수준) +- 트랜잭션이 얼마나 서로 고립되어있는지 나타내는 것 +- 특정 트랜잭션이 다른 트랜잭션에 변경한 데이터를 볼 수 있도록 허용할지 말지를 결정 + +### 격리수준 + - 0레벨 : READ UNCOMMITTED + - 1레벨 : READ COMMITED + - 2레벨 : REPEATABLE READ + - 3레벨 : SERIALIZABLE + +- 아래로 내려갈수록 트랜잭션간 고립 정도가 높아지며, 동시성이 떨어짐(성능 떨어짐) + +### 낮은 격리 수준에서 발생하는 3가지 현상(데이터 부정합 문제) + - Dirty Read : 아직 커밋되지 않은 수정 중인 데이터를 읽을 때 발생 + - Non-Repetable Read : 하나의 트랜잭션에서 동일한 쿼리를 2번 실행했을 때, 그 사이에 다른 트랜잭션이 값을 수정 또는 삭제해 두 쿼리의 결과값이 다르게 나타나는 현상 + - Phantom Read : 하나의 트랜잭션에서 동일한 쿼리를 2번 실행했을 때, 첫 번째 쿼리에서 없던 유령(Phantom) 레코드가 두 번째 쿼리에서 나타나는 현상 +![데이터 부정합](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/데이터%20부정합.jpg?raw=true) + + +## READ UNCOMMITTED +- 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에게 보여짐 +- Dirty Read(더티 리드)가 일어남 + + +- RDBMS 표준에서 트랜잭션의 격리 수준으로 인정하지 않음 +- 정합성에 문제가 많다! +> 정합성 : 데이터가 서로 모순이 없이 일관되게 일치해야 한다는 의미 +![Dirty Read](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/Dirty%20Read.jpg?raw=true)] + + +## READ COMMITTED +- 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있는 격리 수준 +- Oracle에서 기본적으로 사용 +- Dirty Read 방지! +![READ COMMITTED](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/READ_COMMITTED.jpg?raw=true) + +- Oracle의 방식, 이외의 DBMS는 베타 Lock으로 인해 읽기 대기(동시성 제어 추후 정리) +- NON-REPETABLE READ가 일어남 +![Non-Repetable Read](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/Non-Repetable%20Read.jpg?raw=true) + +- 이름이 아닌 계좌의 금액 조회일 경우 금액이 금액의 총합이 다른 결과를 가져올 수 있다! + + +## REPETABLE READ +- 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있는 격리 수준 +- MySQL에서 기본적으로 사용, Oracle은 명시적으로 지원하진 않지만 (for update절을 이용해서 구현 가능) +- NON-REPETABLE READ 방지! +![REPETABLE READ](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/REPETABLE%20READ.jpg?raw=true) + +- MVCC(Multi Concurrency Control) 방식 + - 트랜잭션은 고유 트랜잭션 번호(순차적으로 증가)를 가짐 + - UNDO 영역에 백업된 모든 레코드는 변경이 일어난 트랜잭션 번호를 가짐 + - 변경되기 전 레코드를 UNDO 영역에 백업하고 실제 레코드를 변경 + - 자신의 트랜잭션 번호보다 낮은 트랜잭션 번호에서 변경된(+ 커밋된) 것만 봄 +> 한 트랜잭션의 실행시간이 길어질수록 UNDO 영역의 데이터가 커져 서버 성능의 저하를 초래할 수도 있음 + +- Phantom Read 발생 +![Phantom Read](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/Phantom%20Read.jpg?raw=true) + +- SELECT ~ FOR UPDATE + - 데이터를 수정하기위해 SELECT 중이라는 의미 + - 특정 데이터에 대해 베타적 Lock을 거는 기능(동시성 제어) + - 그러나 INSERT는 공유하기 때문에 첫 번째 쿼리에는 없었던 Phantom Read가 발생 + +> Consistent read +> - 트랜잭션 내부에서 non-locking read(기본 SELECT 구문) 실행할 때, 동시에 실행중인 다른 트랜잭션에서 데이터를 변경하더라도 특정 시점의 스냅샷(snapshot)을 이용하여 기존과 동일한 결과를 리턴할 수 있도록 해주는 기능 +> - MySQL은 이 기능을 사용하기 때문에 Phantom Read가 발생하지 않음 + + +## SERIALIZABLE +- 가장 단순하고 가장 엄격한 격리 수준 +- 동시 처리 성능이 가장 떨어짐 +- 한 트랜잭션에서 읽고 쓰는 레코드를 다른 트랜잭션에서는 절대 접근할 수 없음 +- Phantom Read 방지! +- InnoDB의 경우 REPETABLE READ 격리 수준에서도 Phantom Read 문제가 발생하지 않기 때문에 사용하지 않는 편 + + +## 출처 +- [MySQL 격리 수준(Isolation Level)](https://transferhwang.tistory.com/513) +- [데이터베이스 Transaction & Lock : 네이버 블로그](https://m.blog.naver.com/good_ray/221943028058) +- [MySQL InnoDB Transaction Model 이해하기 | Knowledge Logger](https://www.letmecompile.com/mysql-innodb-transaction-model/) \ No newline at end of file From 27b08768459f8215812bcbba3cb939dfb5c3ed4b Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Sun, 23 Jan 2022 19:25:22 +0900 Subject: [PATCH 11/12] =?UTF-8?q?update:=20=EA=B2=A9=EB=A6=AC=EC=88=98?= =?UTF-8?q?=EC=A4=80=20=EC=88=98=EC=A0=95=20#34?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...51\353\246\254\354\210\230\354\244\200.md" | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git "a/Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" "b/Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" index caf9cf0..c876ef2 100644 --- "a/Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" +++ "b/Database/\352\262\251\353\246\254\354\210\230\354\244\200.md" @@ -19,8 +19,8 @@ ### 격리수준 - 0레벨 : READ UNCOMMITTED - - 1레벨 : READ COMMITED - - 2레벨 : REPEATABLE READ + - 1레벨 : READ COMMITED - (Oracle) + - 2레벨 : REPEATABLE READ - (MySQL) - 3레벨 : SERIALIZABLE - 아래로 내려갈수록 트랜잭션간 고립 정도가 높아지며, 동시성이 떨어짐(성능 떨어짐) @@ -34,12 +34,11 @@ ## READ UNCOMMITTED - 트랜잭션에서의 변경 내용이 COMMIT이나 ROLLBACK 여부에 상관없이 다른 트랜잭션에게 보여짐 -- Dirty Read(더티 리드)가 일어남 - - +- Dirty Read(더티 리드)가 일어남 - RDBMS 표준에서 트랜잭션의 격리 수준으로 인정하지 않음 - 정합성에 문제가 많다! > 정합성 : 데이터가 서로 모순이 없이 일관되게 일치해야 한다는 의미 + ![Dirty Read](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/Dirty%20Read.jpg?raw=true)] @@ -53,29 +52,30 @@ - NON-REPETABLE READ가 일어남 ![Non-Repetable Read](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/Non-Repetable%20Read.jpg?raw=true) -- 이름이 아닌 계좌의 금액 조회일 경우 금액이 금액의 총합이 다른 결과를 가져올 수 있다! +- 이름이 아닌 계좌의 금액 조회일 경우 금액의 총합이 다른 결과를 가져올 수 있다! ## REPETABLE READ - 트랜잭션이 시작되기 전에 커밋된 내용에 대해서만 조회할 수 있는 격리 수준 -- MySQL에서 기본적으로 사용, Oracle은 명시적으로 지원하진 않지만 (for update절을 이용해서 구현 가능) +- MySQL에서 기본적으로 사용, Oracle은 명시적으로 지원하진 않지만 (for update절을 이용해서 구현 가능) -> for update가 oracle에서만 쓸수있는 것은 아님 - NON-REPETABLE READ 방지! ![REPETABLE READ](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/REPETABLE%20READ.jpg?raw=true) -- MVCC(Multi Concurrency Control) 방식 +- MVCC(Multi-Version Concurrency Control) 방식 - 트랜잭션은 고유 트랜잭션 번호(순차적으로 증가)를 가짐 - UNDO 영역에 백업된 모든 레코드는 변경이 일어난 트랜잭션 번호를 가짐 - 변경되기 전 레코드를 UNDO 영역에 백업하고 실제 레코드를 변경 - 자신의 트랜잭션 번호보다 낮은 트랜잭션 번호에서 변경된(+ 커밋된) 것만 봄 > 한 트랜잭션의 실행시간이 길어질수록 UNDO 영역의 데이터가 커져 서버 성능의 저하를 초래할 수도 있음 +> 동일 쿼리가 왜 동일한 트랜잭션 번호를 갖나? -> 같은 트랜잭션이기 때문에 - Phantom Read 발생 ![Phantom Read](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/Phantom%20Read.jpg?raw=true) - SELECT ~ FOR UPDATE - 데이터를 수정하기위해 SELECT 중이라는 의미 - - 특정 데이터에 대해 베타적 Lock을 거는 기능(동시성 제어) - - 그러나 INSERT는 공유하기 때문에 첫 번째 쿼리에는 없었던 Phantom Read가 발생 + - 특정 데이터에 대해 공유 Lock을 거는 기능(동시성 제어) + - 그러나 데이터 변경이 막힌 것일 뿐 새로운 데이터 삽입(INSERT)은 가능하기 때문에 첫 번째 쿼리에는 없었던 Phantom Read가 발생 > Consistent read > - 트랜잭션 내부에서 non-locking read(기본 SELECT 구문) 실행할 때, 동시에 실행중인 다른 트랜잭션에서 데이터를 변경하더라도 특정 시점의 스냅샷(snapshot)을 이용하여 기존과 동일한 결과를 리턴할 수 있도록 해주는 기능 @@ -93,4 +93,5 @@ ## 출처 - [MySQL 격리 수준(Isolation Level)](https://transferhwang.tistory.com/513) - [데이터베이스 Transaction & Lock : 네이버 블로그](https://m.blog.naver.com/good_ray/221943028058) -- [MySQL InnoDB Transaction Model 이해하기 | Knowledge Logger](https://www.letmecompile.com/mysql-innodb-transaction-model/) \ No newline at end of file +- [MySQL InnoDB Transaction Model 이해하기 | Knowledge Logger](https://www.letmecompile.com/mysql-innodb-transaction-model/) +- [MySQL의 Transaction Isolation Levels](https://jupiny.com/2018/11/30/mysql-transaction-isolation-levels/) \ No newline at end of file From c7c0085f20782089477fb55db62530d3899bf3c9 Mon Sep 17 00:00:00 2001 From: leeejuhyeong Date: Sun, 23 Jan 2022 19:33:11 +0900 Subject: [PATCH 12/12] create: [Database] Concurrency Control #48 --- ...4\354\204\261 \354\240\234\354\226\264.md" | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 "Database/\353\217\231\354\213\234\354\204\261 \354\240\234\354\226\264.md" diff --git "a/Database/\353\217\231\354\213\234\354\204\261 \354\240\234\354\226\264.md" "b/Database/\353\217\231\354\213\234\354\204\261 \354\240\234\354\226\264.md" new file mode 100644 index 0000000..14090d7 --- /dev/null +++ "b/Database/\353\217\231\354\213\234\354\204\261 \354\240\234\354\226\264.md" @@ -0,0 +1,173 @@ +# 트랜잭션 +## 목차 +### 1. 트랜잭션 정의 +### 2. Isolation Level +## 3. 동시성 제어(락 메커니즘) +### 4. 교착상태(Dead Lock)와 회복(Recovery) + + +# 동시성 제어(락 메커니즘) +## 요약 +- 다중 사용자 환경 지원을 위해 다중 트랜잭션을 처리하기 위한 제어 방법 +- 많은 사용자가 접근할 수 있고, 응답 시간을 최소로하여 데이터의 무결성과 일관성을 보장하는 것이 목표 + + +## 동시성이란 +- DBMS는 다수의 사용자가 동시에 접근할 수 있음(다중 사용자 환경 지원) +- 따라서 질의문들의 집합인 트랜잭션이 여러 개가 동시에 발생할 수 있음 + + +## 다중 트랜잭션의 문제점 +### Dirty Write(갱신 분실) +- 트랜잭션들이 동일한 데이터를 동시에 갱신하는 경우에 발생 +- 이전 트랜잭션이 갱신한 후 나중 트랜잭션이 해당 데어티를 갱신하여 분실 + +### Cascading Rollback(연쇄 복귀) / Unrecoverability(회복 불가능) +- 여러 개의 트랜잭션이 데이터를 공유할 때, 특정 트랜잭션이 이전 상태로 복귀(rollback)할 경우 아무 문제 없는 다른 트랜잭션까지 연달아 복귀하게 되는 문제 +- 이때 한 트랜잭션이 이미 완료된 상태라면, 트랜잭션의 지속성 조건에 따라 복귀 불가능 + +### Inconsistency(모순성, 불일치 분석) +- 여러 개의 트랜잭션이 동시에 실행할 때 끼어들기로 인해 트랜잭션의 일관성이 유지되지 못하는 상황 + +### Dirty Read(현황 파악 오류) + + +## 동시성 제어 목적 +- 트랜잭션의 직렬성 보장, 동시 수행 트랜잭션 처리량 최대화 +- 공유도 최대, 응답 시간 최소, 시스템 활동의 최대 보장 +- 데이터의 무결성 및 일관성 보장 +> 직렬성 : 트랜잭션들을 병행 처리한 결과가 트랜잭션들을 순차적으로 수행한 결과와 같아지는 성질 -> 시간 순서대로 + + + +## 동시성 제어(Concurrency Control) +- 위의 문제점을 방지하여 정확한 결과를 생성하고 DBMS를 보호하기 위해 트랜잭션의 실행 순서를 제어하는 기법 + +### Lock(락, 로크) + - 동시성을 제어할 수 있도록 모든 DBMS가 공통적으로 Lock 기능을 제공 + - DB 내의 각 데이터 항목과 연관된 하나의 변수, 즉 사용하는 데이터 객체 + +### Lock 단위 + - 한 번에 한 명(트랜잭션)만 사용할 수 있는 단위 + - 예시 - Lock 단위가 파일이라면, 한 사용자가 하나의 파일 데이터를 요청했다면 다른 사용자는 해당 파일 데이터에 접근 불가능 + - 락 단위 ⬆︎, 락의 수⬇︎, 제어 기법 simple, 병행성 ⬇︎ + - 락 단위 ⬇︎, 락의 수 ⬆︎, 제어 기법 complicated, 병행성 ⬆︎ + - 일관성과 동시성의 상관관계 +![일관성, 동시성 상관관계](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/%E1%84%8B%E1%85%B5%E1%86%AF%E1%84%80%E1%85%AA%E1%86%AB%E1%84%89%E1%85%A5%E1%86%BC%2C%20%E1%84%83%E1%85%A9%E1%86%BC%E1%84%89%E1%85%B5%E1%84%89%E1%85%A5%E1%86%BC%20%E1%84%89%E1%85%A1%E1%86%BC%E1%84%80%E1%85%AA%E1%86%AB%E1%84%80%E1%85%AA%E1%86%AB%E1%84%80%E1%85%A8.jpg?raw=true) + + +## 동시성 제어 기법의 종류 +### Locking +- 공유락(Share-Lock, S-Lock) + - 읽기 연산(Read)만 가능 + - 하나의 데이터 항목에 대해 여러 개의 공유잠금이 가능 + - 다른 트랜잭션에 대해 읽기 연산만 공유 +- 배타락(배타락, Exclusive-Lock, X-Lock) + - 읽기 연산(Read), 쓰기 연산(Write) 모두 가능 + - 하나의 데이터 항목에 대해서는 하나의 배타락만 가능 + - 다른 트랜잭션은 읽기, 쓰기 모두 불가능 +![공유락, 베타락](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/%E1%84%80%E1%85%A9%E1%86%BC%E1%84%8B%E1%85%B2%E1%84%85%E1%85%A1%E1%86%A8%2C%20%E1%84%87%E1%85%A6%E1%84%90%E1%85%A1%E1%84%85%E1%85%A1%E1%86%A8.jpg?raw=true) + +- Locking의 한계 + - 직렬 가능한 스케줄이 항상 보장되지 않음 + - 교착상태 발생 +![Locking의 한계](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/Locking%20%E1%84%92%E1%85%A1%E1%86%AB%E1%84%80%E1%85%A8.jpg?raw=true) + + - T14, T15 모두 대기 상태에 들어가 더 이상 진행 ❌ -> 교착상태 발생(DeadLock) + +### 2-Phase Locking(2PL, 2단계 잠금 규약) +- 잠금을 설정하는 단계와 해제하는 단계로 나누어 수행 + - 확장단계(growing phase) : 트랜잭션이 lock을 하면 계속 lock을 해야함 + - 축소단계(shrinking phase) : 트랜잭션이 unlock을 하면 새로운 lock 할수 없음 +- 직렬 스케줄 보장 +- DeadLock(교착상태), Cascading Rollback(연쇄 복귀) 문제 발생 +![2PL](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/2PL.jpg?raw=true) + +### Strict 2 Phase Locking Protocol(엄격한 2단계 잠금 규약) +* 모든 배타적 잠금은 해당 트랜잭션이 완료될 때까지 Unlock을 하지 않음 +* 배타적 잠금의 Unlock을 트랜잭션이 완료될 때 수행 +* Cascading Rollback(연쇄 복귀)가 발생하지 않음 +* DeadLock 발생 + +### Rigorous 2 Phase Locking Protocol +* 모든 Lock은 트랜잭션이 완료될 때까지 Unlock을 하지 않음 +* Strict 2PLP보다 제한적 +* DeadLock 발생 + +### Static 2 Phase Locking Protocol +* 트랜잭션의 실행 전에 트랜잭션의 모든 읽기/쓰기 집합을 선언하고 모두에 대한 Lock을 획득 +* DeadLock이 발생하지 않음 +* 현실성이 없음 +* 대부분의 상용 DBMS는 동시성 제어를 위해 Strict 2PLP나 Rigorous 2PLP를 사용 + +> 2PL 이후는 이런게 있다로 이해하면 될 것 같음 + +- 구조 +![2PL 구조](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/2PL%20%E1%84%80%E1%85%AE%E1%84%8C%E1%85%A9.jpg?raw=true) + + - Lock Table은 각 데이터 항목의 이름으로 인덱스된 해시테이블 구조를 가짐 + - 각 데이터 항목은 lock을 가지고 있는 트랜잭션과 lock을 기다리는 트랜잭션의 list를 갖고 있음 + +### Timestamp Ordering +- 각 트랜잭션이 시스템에 들어오는 순서대로 시스템에서 생성하는 고유 번호인 타임스탬프를 부여하여 순서를 지정 +- 먼저 들어온 트랜잭션에게 우선권을 부여(낮은 번호) +- DeadLock 방지하지만 장기 트랜잭션 철회 시 자원 낭비가 큼 +- 동작 원리 + - 수행중인 트랜잭션의 타임 스탬프와 튜플에 기록된 타임스탬프를 비교. + - 튜플에는 마지막 Read나 Write의 타임스탬프가 기록되어 있음 +- Last Read Timestamp + - Write 트랜잭션의 TS가 마지막 ReadTS보다 작으면 Rollback + - 나중에 읽었다고 표시가 되어 있으므로 수정하면 안됨(Dirty Read 방지) +- Last Write Timestamp + - Write, Read 트랜잭션의 TS가 마지막 Write TS보다 작으면 Rollback + - 나중에 수정할 튜플이므로 읽거나 수정하면 안됨(Dirty Read 방지) + +### MVCC(Multi-Version Concurrency Control) +- Lcok의 경우 해당 데이터를 선점한 사용자가 Unlock할때까지 해당 데이터를 컨트롤하는데 제약이 있음 +- Timestamp Ordering의 경우 Roallback이 빈번 +- 이를 보완하고자 트랜잭션 마다 Multi-Version으로 만든 것 +- 이 Multi-Version으로 인해 각 트랜잭션마다 원래 상태의 데이터베이스(Snapshot)로 접근 및 사용할 수 있게 됨 +- Undo 오버헤드(snapshot too old) 문제, 연쇄 복구 여전 +- 유형 + - 유형 1 : 기존 데이터 삭제표시, Heap영역에 저장 + - 데이터베이스 내에 다중 버전의 데이터를 저장 + - 기존 데이터는 삭제 표시, 더이상 필요하지 않을 때 데이터 정리 + - 단점 : 데이터가 많아지는 형식으로 파일 사이즈가 계속 증가 + - PostgreSQL, SQL Server, CUBRID +![MVCC 유형1](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/MVCC%20%E1%84%8B%E1%85%B2%E1%84%92%E1%85%A7%E1%86%BC1.jpg?raw=true) + + - 유형 2 : Snapshot 적용, SCN으로 트랜잭션 순서확인, Undo영역에 저장 + - DB에는 최신 버전의 데이터만 저장 + - 이전 데이터는 Undo 영역에 백업 + - 데이터 갱신시 Undo 영역에는 이전 데이터블럭들값과 당시의 SCN(System Commit Number)가 저장, Timestamp처럼 트랜잭션 순서로 읽어옴 + - Oracle, MySQL +![MVCC 유형2](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/MVCC%20%E1%84%8B%E1%85%B2%E1%84%92%E1%85%A7%E1%86%BC2.jpg?raw=true) + +- 구조 + - 페이지 + - MVCC 저장공간 + - 페이지는 페이지 헤더와 튜플을 가리키는 포인터를 갖고있음 +![MVCC 페이지 구조](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/MVCC%20%E1%84%91%E1%85%A6%E1%84%8B%E1%85%B5%E1%84%8C%E1%85%B5%20%E1%84%80%E1%85%AE%E1%84%8C%E1%85%A9.jpg?raw=true) + +> Snapshot : 트랜잭션이 시작되어 DB에 변경될 때 일관성을 위해 UNDO에 저장, 이를 통해 트랜잭션 마다 시작상태의 DB로 접근이 가능하다. 이를 온전한 DB를 사진을 찍어서 보여준다는 의미로 Snapshot이라는 표현을 사용. 각각의 트랜잭션들은 각각의 다른 Snapshot을 보게 된다 +> MVCC에서 Snapshot을 가져오는 방법은 트랜잭션의 시작 시간정보인 SCN과 페이지 내 튜플헤더에 저장된 공간정보 XID로 가져온다. 더 자세한 정보는 [DATABASE MVCC 구조와 이해](https://mozi.tistory.com/561)여기서.. + +### 정리(요약) +![동시성 제어 요약](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/%E1%84%83%E1%85%A9%E1%86%BC%E1%84%89%E1%85%B5%E1%84%89%E1%85%A5%E1%86%BC%20%E1%84%8C%E1%85%A6%E1%84%8B%E1%85%A5%20%E1%84%8B%E1%85%AD%E1%84%8B%E1%85%A3%E1%86%A8.jpg?raw=true) + +### 비교 +![동시성 제어 비교](https://github.com/leeejuhyeong/images/blob/main/no-study-no-future/Database/%E1%84%83%E1%85%A9%E1%86%BC%E1%84%89%E1%85%B5%E1%84%89%E1%85%A5%E1%86%BC%20%E1%84%8C%E1%85%A6%E1%84%8B%E1%85%A5%20%E1%84%87%E1%85%B5%E1%84%80%E1%85%AD.jpg?raw=true) + + + +## 출처 +- [데이터베이스 Transaction & Lock : 네이버 블로그](https://m.blog.naver.com/good_ray/221943028058) +- [동시성 제어 : 꿈꾸는 개발자, DBA 커뮤니티 구루비](http://www.gurubee.net/lecture/2398) +- [동시성 제어 기법 — Locking, 2PL | by 이예원 | POCS | Medium](https://medium.com/pocs/%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%A0%9C%EC%96%B4-%EA%B8%B0%EB%B2%95-%EC%9E%A0%EA%B8%88-locking-%EA%B8%B0%EB%B2%95-319bd0e6a68a) +- [데이터베이스 동시성 제어 종류 > 도리의 디지털라이프](http://blog.skby.net/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%A0%9C%EC%96%B4/) +- [2PL 종류 : HYEEWON/web-backend-study · GitHub](https://github.com/HYEEWON/web-backend-study/blob/main/database/transaction.md) +- [Timestamp Ordering 기법. 동작 원리에 대한 개요 | by Kyungmin Kim(김경민) | myInterest | Medium](https://medium.com/myinterest/timestamp-ordering-%EA%B8%B0%EB%B2%95-c66b57bae978) +- [DATABASE MVCC 구조와 이해](https://mozi.tistory.com/561) +- [MVCC에 관하여 정리](https://this1.tistory.com/entry/MVCC%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC-%EC%A0%95%EB%A6%AC) +- [into MySQL: InnoDB MVCC의 개요](http://intomysql.blogspot.com/2010/12/innodb-mvcc.html) +- [MVCC 메커니즘 - Snapshot](https://neulpeumbomin.tistory.com/10) \ No newline at end of file