- Published on
[ASAC 스터디] Spring
- Authors
- Name
- Chan Sol OH
목차
- [복합] Spring DI/IoC는 어떻게 동작하나요?
- 복합 Spring Bean이란 무엇인가요?
- DI 종류는 어떤것이 있고, 이들의 차이는 무엇인가요?
- Autowiring 과정에 대해서 설명해주세요.
- 스프링 프레임워크에서 사용되는 디자인 패턴에는 어떤 것들이 있나요?
- [복합] Spring Web MVC의 Dispatcher Servlet의 동작 원리에 대해서 간단히 설명해주세요.
- Servlet Filter와 Spring Interceptor를 설명하고 차이를 알려주에요
- Spring에서 CORS 에러를 해결하기 위한 방법을 설명해주세요.ㆍ
- POJO란 무엇인가요? Spring Framework에서 POJO는 무엇이 될 수 있을까요?
- Spring Web MVC에서 요청 마다 Thread가 생성되어 Controller를 통해 요청을 수행할텐데, 어떻게 1개의 Controller만 생성될 수 있을까요?
- Spring WEB MVC의 근간에는 Java Servlet 이 있는데요. Spring 은 Servlet을 어떻게 구성해서 이를 구현했을까요?
- @RequestMapping 애노테이션은 어떻게 사용하나요?
- Spring Application을 구동할 때 메서드를 실행시키는 방법에 대해 설명해주세요.
- spring과 spring boot 차이에 대해 알려주세요.
- 스프링 DAO란 무엇인가요?
- 스프링 JDBC의 JdbcTemplate 클래스는 무엇이고 어떻게 사용하나요?
- JPA를 쓴다면 그 이유에 대해서 설명해주세요.
- 스프링 트랜잭션을 구현하기 위한 다양한 방법을 말해주세요.
- Hibernate의 sessionfactory와 session은 무엇인가요?
- JPA 영속성 컨텍스트의 이점(5가지)을 설명해주세요.
- JPA Propagation 전파단계를 설명해주세요.
- N + 1 문제는 무엇이고 이것이 발생하는 이유와 이를 해결하는 방법을 설명해주세요.
[복합] Spring DI/IoC는 어떻게 동작하나요?
- 스프링 컨테이너의 역할도 알려주세요.
- Application context가 뭔지도 알려주세요.
- IoC 컨테이너의 역할은 무엇이 있을까요?
- Bean/Component 어노테이션에 대해서 설명해주시고, 둘의 차이점에 대해 설명해주세요.
IoC는 객체나 프로그램의 일부분을 컨테이너나 프레임워크가 개발자 대신 관리하는 SW 원칙입니다. 프레임워크는 추상적인 동작을 빌트-인으로 제공하고, 개발자는 필요하다면 확장
을 통해 원하는 바로 동작시킬 수 있습니다. IoC를 사용하면 구현과 실행 작업을 분리할 수 있고, 다른 구현체를 쉽게 바꿔낄 수 있습니다. 또한, 컴포넌트들을 격리해서 분리하기 때문에 테스트 프로그램을 작성하기 쉽습니다.
DI는 객체 간의 의존성을 코드에 직접 작성하는 것 대신 외부에서 관리하도록하는 디자인 패턴입니다. DI는 IoC를 구현하는 것으로, 설정된 객체 관계에 따라 프레임워크가 주입시켜줍니다.
Spring IoC 컨테이너는 IoC를 구현한 대표적인 프레임워크입니다. ApplicationContext
인터페이스는 IoC 컨테이너를 표현합니다. Spring 컨테이너는 bean이라는 객체를 인스턴스화, 구성, 그리고 어셈블하고, 수명주기에 따라 관리합니다.
Spring 프레임워크는 ApplicationContext
인터페이스의 여러 구현체를 제공합니다. AnnotationConfigApplicationContext
, WebApplicationContext
같은 것들이 있습니다. 특히 AnnotationConfigApplicationContext
는 @Bean
같은 특정 어노테이션이 붙은 클래스를 스캔, 초기화 관리를 담당합니다.
spring 컨테이너가 bean을 관리하도록 설정하는 어노테이션은 @Bean
과 @Component
가 있습니다. 두 어노테이션 모두 인스턴스를 초기화하고 다른 클래스에 주입할 수 있도록 autowire해줍니다.
그렇다면 둘의 차이는 뭘까요? 바로 @Bean
은 메서드 레벨에서 객체를 생성하고 그 객체를 bean으로 관리할 수 있게하고, @Compoenet
는 클래스 레벨에서 어노테이션이 붙은 클래스를 인스턴스로 초기화해 bean으로 관리합니다. java는 메서드 단독으로 인스턴스로 만들 수 없기 때문에 보통 @Bean
을 사용하기 위해선 @Configuration
을 메서드를 포함하는 클래스에 붙입니다.
만약 외부 라이브러리에서 가져온 클래스를 bean으로 관리하고 싶다면 어떻게 해야할까요? 바로 외부 클래스를 생성하는 메서드에 @Bean
어노테이션을 붙여서 인스턴스를 관리할 수 있게합니다.
복합 Spring Bean이란 무엇인가요?
- 빈의 생명주기도 알려주세요.
- 스프링 Bean의 Scope에 대해서 설명해주세요.
life cycle이라는 것은 객체가 어떻게 생성되고 어떻게 사용되고 어떻게 제거되는지를 의미합니다. bean의 life cycle은 spring 컨테이너가 관리합니다. 아래는 spring 컨테이너 생성부터 bean life cycle을 순서대로 작성했습니다.
- 프로그램이 시작되면 spring 컨테이너가 생성됩니다.
- spring 컨테이너는 요청(스캔)에 따라 인스턴스를 생성하고 의존성을 주입합니다.
- 최종적으로 spring 컨테이너가 종료되면 인스턴스들도 제거됩니다.
스프링은 여러 스코프를 가집니다.
- 싱글톤 : 기본 설정으로, 오직 하나의 인스턴스만 여러 쓰레드가 공유해서 사용합니다.
- 프로토타입 : 인스턴스를 초기화하고 의존성을 주입하는 것까지만 spring 컨테이너가 하는 것은 싱글톤과 같지만, 요청 마다 새로운 bean을 만들어서 주는 차이점이 있습니다. 만약 싱클톤 타입의 bean이 프로토타입의 bean을 주입해 사용한다면, 처음 생성한 프로토타입을 프로그램이 종료될 때까지 사용하는 위험도 있습니다.
- request : 웹 스코프로 HTTP 요청이 들어오고 나갈 때까지 유지됩니다. 각 HTTP 요청마다 별도의 인스턴스로 bean을 생성합니다.
- session : 웹 스코프로 HTTP session과 동일한 생명 주기를 가집니다.
- websocket : 웹 스코프로 웹 소캣과 동일한 생명 주기를 가집니다.
DI 종류는 어떤것이 있고, 이들의 차이는 무엇인가요?
- 의존성과 설정값을 생성자 인자로 주입해야 하는 이유에 대해 설명해주세요.
생성자 주입은 객체를 만들 때, 생성자의 인자 타입에 맞는 bean을 spring 컨테이너에서 찾아 주입합니다. 만약 한 타입의 bean이 여러개 있다면 순서대로 주입하거나 설정을 통해 특정 bean을 주입하게할 수 있습니다.
setter 주입은 컨테이너가 setter 메서드를 통해 의존성을 주입합니다. 처음 인스턴스 생성할 때는 기본 생성자로 만들고, 그 다음 주입합니다. 문제는 setter는 개발자가 임의로 다른 값을 주입시킬 수 있어서 위험할 수 있습니다.
Autowiring 과정에 대해서 설명해주세요.
- @Compoent와 @Autowired의 관계
spring 컨테이너는 @Autowire
이 적혀있는 곳이나 Xml에 설정된 것에 따라 의존성 주입을 해줍니다. @SpringBootApplication
이 붙으면 패키지 내 하위 클래스들을 스캔하면서 @Compoenet
나 @Bean
을 bean으로 관리하게 됩니다.
스프링 프레임워크에서 사용되는 디자인 패턴에는 어떤 것들이 있나요?
- Proxy : 어떤 객체에 접근을 중간에 가로채서 시작과 끝에 특정한 조작을 추가합니다. AOP가 비즈니스 로직과 부가 로직을 분리하기 위해 적용합니다.
- Singleton : 어떤 객체를 단 하나만 생성해서 공유합니다. spring에서는 bean을 관리할 때 적용하고 DI할 때 생성한 bean을 주입합니다.
- Template Method : 슈퍼클래스에 기본적인 로직을 작성하고, 일부 변경이 필요한 부분에는 추상 메서드로 둬서 서브클래스가 오버라이딩할 수 있게해 중복을 최소화할 수 있습니다. JDBC는 여러 DB 밴더에 따라 드라이버가 달라지지만, 코드 중복을 최소화하기 위해 JdbcTemplate은 템플릿 메서드로 작성됐습니다.
- Factory Method : 객체 생성을 생성자가 아닌 별도의 클래스 또는 메서드로 분리해서 객체 생성을 추상화할 수 있습니다. 또한 비슷한 종류의 클래스를 모아서 하나의 팩토리에서 생성하게 할 수도 있습니다. 가장 대표적으로 logger를 팩토리로 생성하게합니다.
- MVC : 아래에 설명했습니다.
- Front Controller : 아래에 설명했습니다.
[복합] Spring Web MVC의 Dispatcher Servlet의 동작 원리에 대해서 간단히 설명해주세요.
- MVC 패턴은 무엇있까요?
- 프론트 컨트롤러 패턴이란 무엇인가요?
MVC 패턴은 모델, 뷰, 컨트롤러 3가지 요소로 사용자에게 화면이나 데이터를 제공하는 패턴입니다. 모델은 애플리케이션 데이터를 캡슐화하고, 뷰는 데이터를 화면에 표현하는 것이고, 마지막 컨트롤러는 모델을 뷰에 주입시켜 화면을 사용자에게 전달합니다.
프론트 컨트롤러는 클라이언트로 부터 어떤 요청이 들어오면, 프론트 컨트롤러가 어떤 컨트롤러에게 요청을 전달할지 결정합니다.
Dispatcher Servlet은 들어오는 HttpRequest를 spring application에 구현된 HandlerAdapter의 설정에 따라 처리합니다. 이때 어떤 핸들러, 어떤 컨트롤러 엔드포인트, 어떤 응답 형태를 사용할지도 전달합니다. 아래 순서에 따라 Dispatcher Servlet이 요청을 처리합니다.
- DispatcherServlet이 모든 HandlerAdapter의 구현체를 찾습니다.
- LocaleResolver, ThemeResolver는 각각 요청 응답의 현지 또는 Theme을 바인딩해줍니다.
- HandlerExceptionResolver는 요청을 처리하는 동안 예외를 선택해 처리합니다.
SimpleControllerHandlerAdapter
는@Controller
가 붙은 클래스 속 컨트롤러를 사용할 수 있게하고RequestMappingHandlerAdapter
는@RequestMapping
이 붙은 컨트롤러에 적용합니다.- ViewResolver는 DispatcherServlet이의 요청에 따라 어떤 종류의 뷰가 선택되고 어디에 뷰를 제공할지 결정합니다.
Servlet Filter와 Spring Interceptor를 설명하고 차이를 알려주에요
Java Servlet Filter는 클라이언트의 요청을 가로채고 pre-processing하는 작업을 수행합니다. 또한 응답도 가로채서 post-processing을 할 수 있습니다. Servlet 속성은 세션이 살아있는 동안 사용합니다. 만약 Servlet 속성을 바꿔줘야한다면 session authentication을 사용하는 모든 코드를 수정해야합니다. Servlet Filter는 플러깅이 가능하고 요청의 전후를 가로채서 작업을 추가하는 java 컴포넌트입니다. Servlet과 Filter는 서로 인지하지 못하고 단지, web.xml을 통해 필터를 추가 삭제할 수 있습니다. 또한 여러 필터를 체이닝해서 web.xml에 설정할 수 있습니다.
Spring HandlerMapping는 URI와 메서드를 맵핑해줍니다. interceptors는 불필요하게 추가적인 핸들러를 사용하지 않고 요청을 가로채 인증이나 로깅 같은 작업을 수행합니다. 또한 HandlerInterceptor는 Servlet Filter와 비슷하게 핸들링 이전, 이후, 그리고 뷰가 완전히 생성되고 난 후 작업을 수행할 수 있게합니다.
Servlet Filter와 Interceptor는 차이는 java의 servlet container에서 실행되는지 Spring Context에 접근하는 요청에 대해 실행되는지 차이입니다. 따라서 항상 Servlet Filter를 통과하고 HandlerAdapter를 지나 Context에 bean에 메서드까지 요청이 흘러들어갑니다.
실행범위에도 차이가 있는데 Filter는 Servlet 단위로 적용되고, Interceptor는 컨트롤러 단위로 적용됩니다.
Spring에서 CORS 에러를 해결하기 위한 방법을 설명해주세요.ㆍ
CorsConfiguration
에 허용할 url과 http method 설정을 통해 가능합니다. 이는 CorsWebFilter를 설정할 수 있고, CorsWebFilter는 설정에 따라 CORS preflight requests를 핸들링할 수 있고, CORS simple을 가로챌 수 있습니다.
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
- @CrossOrigin(origins = "http://front-server.com") // 컨트롤러에서 설정 클래스 메서드 다 가능
POJO란 무엇인가요? Spring Framework에서 POJO는 무엇이 될 수 있을까요?
POJO는 어떤한 명명 규칙이 없이 특정 프레임워크에 의해 관리되지 않는 순수한 자바 클래스를 말합니다. 오직 Java만 의존하며 다른 프레임워크에 의존하지 않습니다. 이를 통해 재사용성과 가독성 그리고 테스트 용이성을 높입니다.
만약 특정 기술에 의존한 클래스를 사용하다가 기술을 바꾸려면 클래스의 모든 부분을 바꿔야하는 문제가 발생합니다. 따라서 비즈니스 로직을 담고 있는 부분은 POJO로 해야지 특정 인터페이스나 클래스에 의존하면 안됩니다. Spring에서는 최대한 기술에 종속적이지 않도록 POJO를 사용하고 비즈니스 로직의 재사용성을 높이기 위해 IoC, DI, PSA 같은 방법을 사용합니다.
예를 들어 Spring JDBC를 Spring MVC 없이 사용할 수 있는 것처럼 JPA의 Transactional 어노테이션을 붙여도 각기 다른 DBMS에 맞게 트랜젝션을 적용시키는 것처럼 IoC와 DI를 조합해 PSA를 구현해 사용합니다. 또한 컨트롤러와 서비스를 분리해 비즈니스 로직을 POJO로 관리하면 비즈니스 로직을 프레임워크에 독립적으로 관리할 수 있습니다.
Spring Web MVC에서 요청 마다 Thread가 생성되어 Controller를 통해 요청을 수행할텐데, 어떻게 1개의 Controller만 생성될 수 있을까요?
Spring은 기본적으로 객체를 싱글톤 패턴으로 생성하기 때문에 1개만 생성하고 Spring container에 관리합니다. 따라서 Controller 객체도 1개만 생성하고 관리합니다.
멀티스레드가 한 Controller 빈에 요청할 수 있는 이유는 메모리 상 메소드 영역에 클래스 정보가 저장되고 메소드 영역은 모든 스레드가 접근할 수 있습니다. 또한 Controller가 무상태성을 가진다면 스레드끼리 동기화할 필요가 없기 때문에 스레드 안전하게 사용할 수 있습니다. 정리하면 각 스레드가 한 Controller의 메서드를 실행시켜서 각 요청을 처리합니다.
Spring WEB MVC의 근간에는 Java Servlet 이 있는데요. Spring 은 Servlet을 어떻게 구성해서 이를 구현했을까요?
- 스프링 빈에서 ServletContext와 ServletConfig 객체는 어떻게 얻나요?
Java Servlet은 java 웹 애플리케이션 서버에서 실행되는 프로그램입니다. 웹 서버로 부터 얻은 요청을 조작하고 응답을 생성하여 웹 서버에게 전달하는 역할을 가집니다. Servlet은 java로 구현되어 있어 플랫폼에 독립적이고 한 프로세스에서 여러 servlet을 멀티스레드로 실행시키기 때문에 메모리 사용량을 줄입니다. Servlet Container는 클라이언트의 http 요청을 java api 요청으로 변환하고 각 요청을 서블릿이 처리할 수 있도록 서블릿을 생성하고 서블릿 메소드를 호출합니다. 요청을 전부 해결하면 서블릿을 소멸시켜 GC가 메모리 제거하도록합니다.
Spring MVC는 DispatcherServlet이라는 메인 서블릿을 가지고 있고, 이 서블릿은 모든 요청을 받고 적절한 채널로 전달합니다. DispatcherServlet은 Servlet Container 역할처럼 요청의 처리를 적절한 빈에 위임할 수 있습니다. HTTP 요청을 받아 처리하는 방법 중에 개발자가 직접 web.xml
에 서블릿을 등록하거나 @ServletComponentScan
을 통해 등록하는 방법이 있지만, 편의성 때문에 @Controller
로 DispatcherServlet이 HandlerMapping을 통해 찾은 적절한 빈에 처리를 위임하도록 하는 방법을 사용합니다.
Spring에서는 WebApplicationInitializer
가 구현을 감지해서 자동으로 servlet container를 초기화합니다. ServletConfig는 Servlet 객체를 초기화할 때 생성됩니다. 또한 Servlet이 실행 중일 때만 ServletConfig를 사용할 수 있습니다. ServletContext는 웹 애플리케이션 실행 단계에서 생성되고 글로벌하게 사용할 수 있습니다. 그리고 애플리케이션이 종료될 때 제거됩니다.
spring에서는 @Autowired
를 사용하거나 ServletContextAware와 ServletConfigAware를 사용해서 빈을 얻을 수 있습니다.
@RequestMapping 애노테이션은 어떻게 사용하나요?
value에 URI를 작성하고 method에 HTTP 메서드를 작성하고 produces에 Response의 Content-Type을 결정할 수 있습니다.
@RequestMapping(
value = "/ex/foos",
method = GET,
produces = { "application/json", "application/xml" }
)
Spring Application을 구동할 때 메서드를 실행시키는 방법에 대해 설명해주세요.
- command line runner와 application runner와 관련지어서 설명해주세요
Spring application이 시작할 때 어떤 로직을 실행할 때는 아직 빈이 생성되지 않았음을 유의해야합니다. 따라서 @Autowired
같은 생성자에 빈을 주입하는 IoC도 불가합니다.
@PostConstruct
같은 어노테이션을 이용해서 빈이 초기화 됐을 때 주입할 수 있습니다.InitializingBean
인터페이스의afterPropertiesSet()
를 구현하면 어노테이션을 붙일 필요 없이 초기화된 빈을 주입할 수 있습니다.ApplicationListener
인터페이스를 구현하거나@EventListener
를 사용해 특정 이벤트(exContextRefreshedEvent
)가 발생할 때 로직을 수행할 수 있습니다.CommandLineRunner
와ApplicationRunner
인터페이스는 Spring application context가 초기화되고 난후run()
메서드를 실행시킵니다.
spring과 spring boot 차이에 대해 알려주세요.
spring의 가장 큰 특징으로 DI와 IoC 그리고 이를 통해 애플리케이션 간 느슨한 결합을 구현해 유지보수성과 테스트 용이성을 올린 것입니다. 또한 xml과 어노테이션 설정을 통한 선언적 프로그래밍을 지원합니다.
Spring Boot는 내장된 웹 서버를 이용해서 쉽게 앱을 배포할 수 있고, Starter 의존성을 통해 자동으로 미리 설정된 앱을 통해 쉽게 빌드할 수 있습니다. 이를 통해 기존 방대한 XML 설정을 하지 않아도 됩니다. 하지만, 필요에 따라 개발자가 기본 설정을 바꿀 수 있습니다.
스프링 DAO란 무엇인가요?
Data Access Object(DAO)는 데이터베이스의 조작을 전담하며 DB에 접근할 때 사용하는 기술(JDBC, JPA)을 추상화하기 위해 사용합니다. @Repository
를 붙여 Spring에서 DAO나 Repository에 대한 예외를 자동으로 DataAccessException로 던질 수 있게합니다. 서비스 레이어와 Persistence 레이어를 분리하는 인터페이스로 서비스 레이어에서 예외를 일관되게 처리할 수 있게합니다.
스프링 JDBC의 JdbcTemplate 클래스는 무엇이고 어떻게 사용하나요?
JDBC는 어떻게 클라이언트가 DB에 접근할지 정의하는 API입니다. 또한 DB에 쿼리하거나 업데이트하는 메서드를 제공합니다. DB 벤터에 따라 드라이버가 다르기 때문에 JDBC API는 JDBC 드라이버가 필요합니다. 하지만 쿼리를 실행시기키 전, 후에 연결 생성, 문장 생성, result-set 조작, 연결 해제 같은 보일러플레이트 코드가 많습니다.
Spring JDBC Template은 JDBC의 문제점을 제거해줍니다. SQL 요청, 자동 result-set 조작 그리고 JDBC 예외를 처리할 수 있습니다. 데이터 클래스와 그에 따른 DAO 인터페이스 그리고 DAO를 JdbcTemplate으로 구현하면 DB에서 받아온 result-set을 Mapper가 데이터 클래스 형태로 테이블-객체 맵핑을 수행합니다.
JPA를 쓴다면 그 이유에 대해서 설명해주세요.
JPA를 사용하는 이유는 무엇 보다도 테이블 형테의 데이터를 객체 형태로 관리하고 조작하기 위함입니다. 그렇기 때문에 Object Relational Mapping 프레임워크라고 합니다. JPA가 객체의 조작에 따라 SQL을 생성해주기 때문에 이미 SQL이나 data model이 존재하면 JPA는 적절하지 않을 수 있습ㄴ디ㅏ.
스프링 트랜잭션을 구현하기 위한 다양한 방법을 말해주세요.
Transaction은 글로벌 Transaction과 로컬 Transaction이 있습니다. JTA 같은 글로벌 Transaction은 애플리케이션 전역에 걸친 여러 transactional 자원을 관리할 수 있지만 복잡하고 재사용성이 낮은 코드를 작성해야합니다. JDBC 같은 로컬 Transaction은 특정 자원에 대해서만 관리하지만, 쉽게 사용할 수 있습니다.
@Transactional
은 Spring Boot application이 트랜젝션을 관리하도록 합니다. 트랜젝션 관리는 임시로 DB 조작 데이터를 메모리 상에 저장하고 정상적으로 완료하면 트랜젝션을 완성시키고 실패하면 롤백시켜 DB에 데이터를 저장하지 않습니다.
메서드 안에서 entityManager
를 이용해 트랜젝션 시작하고 커밋할 수 있습니다. 트랜젝션이 시작되면 Persistence Context에 엔티티를 저장, 업데이트, 삭제하고 커밋하면 변경 사항들이 DB에 적용됩니다.
Hibernate의 sessionfactory와 session은 무엇인가요?
JPA의 entityManagerFactory를 Hibernate의 sessioFactory가 상속하고 JPA의 entityManager를 session이 상속합니다. Hibernate는 JPA의 구현체이기 때문에 JPA의 각각 요소의 역할과 sessionfactory와 session의 역할은 유사합니다.
프로그램은 하나의 SessionFactory를 가지고 SessionFactory는 클라이언트 요청에 따라 session 인스턴스를 제공합니다. 그리고 트랜젝션이 커밋되거나 요청이 끝나면 session 인스턴스를 제거합니다. 또한 설정에 따라 pooling된 JDBC 연결 및 트랜젝션의 수명주기를 관리합니다.
JPA 영속성 컨텍스트의 이점(5가지)을 설명해주세요.
Persistence context는 엔티티 인스턴스들의 집합체입니다. 그 안에서 엔티티 인스턴스의 생명주기가 관리되고 EntityManager는 Persistence Context 안에 엔티티에 대한 생성, 삭제, 조작을 가합니다.
- Persistence Context는 DB에서 불러오거나 저장하는 엔티티를 1차로 캐시하는 역할을 할 수 있습니다. Transaction 안에서 수행한 조작은 따로 DB에 쿼리하지 않아도 캐싱되어 언제든지 불러올 수 있습니다.
- Persistence Context에 저장된 인스턴스들은 모두 유니크함을 보장합니다.
- write-behind, Persistence Context는 transaction 동안 엔티티에 가해지는 조작을 인지하고 있다가 끝나면 Persistence Storage에 저장합니다. 이는 조작이 있을 때마다 DB에 요청하지 않고 한번에 요청하기 때문에 DB 오버헤드를 줄일 수 있습니다.
- Dirty checking, Persistence는 조작을 계속 저장하고 있기 때문에 따로 업데이트 쿼리를 하지 않더라도 수정 사항이 Persistence Storage에 반영됩니다.
- DB에 쿼리할 때 연관 테이블까지 모두 join하지 않고 프록시 객체를 가져오는 Lazy Loading을 지원합니다. 매번 join하지 않아 DB 오버헤드를 줄일 수 있고, 필요할 때 따로 쿼리할 수 있기 때문에 성능적인 이점이 있습니다.
JPA Propagation 전파단계를 설명해주세요.
Transaction의 propagation을 참고해주세요.
- Required : 이미 transaction이 존재하면 사용하고 없으면 생성, 기본 설정
- Supports : 이미 transaction이 존재하면 사용하고 없으면 transaction 없이 수행합니다.
- Mandatory : 이미 transaction이 존재하면 사용하고 없으면 예외를 발생시킵니다.
- Never : 이미 transaction이 존재하면 예외를 발생시킵니다.
- Not_Supported : 이미 transaction이 존재하면 보류시키고 transaction 없이 수행합니다.
- Required_new : 항상 새로운 transaction을 생성합니다.
- Nested : 이미 transaction이 존재하면 save point를 생성하고 예외가 발생하면 save point로 롤백합니다.
N + 1 문제는 무엇이고 이것이 발생하는 이유와 이를 해결하는 방법을 설명해주세요.
N+1 문제는 객체와 테이블의 형태 차이에서 발생하는 ORM의 근본적인 문제입니다. N+1 문제는 한 엔티티를 쿼리했을 때 특정 테이블에 Select
쿼리를 보내고 다른 연관관계에 있는 테이블에 다시 Select
쿼리를 보내는 것입니다. 이렇게 되면 application은 한 엔티티를 쿼리했을 뿐인데 DB는 여러번 쿼리를 받게되어 오버헤드가 늘어납니다.
이를 해결하기 위해 Hibernate에서 생성하는 sql문 대신에 명시적으로 fetch join하는 jpql 문을 작성해서 쿼리를 최적화할 수 있습니다. fetch join하는 방법은 테이블을 join하는 것이기 때문에 똑같은 1:N 관계 상에서 1을 가진 테이블의 값이 중복해서 가져올 수 있습니다. 또한 페이징을 수행할 때 모든 row를 불러와 애플리케이션 메모리에 저장하고 페이징을 처리합니다.
Batch Size
를 사용하면 정해진 개수 만큼만 DB에서 row를 불러오기 때문에 페이징에 유리합니다. 다만, 쿼리하는 row의 개수가 정해진 개수 이상이라면 쿼리가 여러번 나가게 됩니다. 이때는 fetch join이 유리할 것입니다.
쿼리를 최적화하는 또 다른 방법으로 fetch join이 아닌 일반 join으로 여러 테이블을 join하고 Projection
을 통해 엔티티가 아닌 DTO를 직접 쿼리할 수 있습니다. 이렇게 하면 DB에서 전달할 데이터가 줄어드니 네트워크 오버헤드가 줄어들고 커버링 인덱스가 적용되어 쿼리 성능이 향상됩니다.