핵심개념이해 4
- JPA repository 원리
- 직접 repository 를 만들어봄으로써 자동으로 해주는 작업들이 뭔지 알아보기
- 자동으로 해주는 작업들의 작동 원리 알아보기
- JPA 사용시 유의할 점
JPA repository 원리
직접 repository 를 만들어봄으로써 자동으로 해주는 작업들이 뭔지 알아보기
아래와 같이 JpaRepository 를 상속하면 기본적인 CRUD 오퍼레이션들을 repository 로 사용할 수 있다. 그리고 명시적으로 @Repository 로 설정해주지 않아도 자동으로 bean 으로 등록까지 된다.
public interface PostRepository extends JpaRepository<Post, Long> {
}
위의 일련의 과정을 그저 ‘이렇게 하면 Spring이 알아서 해준다’가 아니라 조금 더 자세히 들여다보자.
먼저 위의 방법이 아니라 실제로 EntityManager 를 이용해서 Repository 를 직접 만들어보자.
@Repository
@Transactional
public class PostRepository {
@PersistenceContext
private EntityManager entityManager;
public Post save(Post post) {
entityManager.persist(post);
return post;
}
public Optional<Post> findById(Long id) {
return Optional.of(entityManager.find(Post.class, id));
}
}
@Component
public class JpaRunner implements ApplicationRunner {
@Autowired
private PostRepository postRepository;
@Override
@Transactional
public void run(ApplicationArguments args) throws Exception {
Post post = new Post();
post.setName("첫번째 포스팅");
postRepository.save(post);
}
}
간단한 예제이지만 이렇게 직접 Repository 를 만들어보면 extends JpaRepository<Post, Long>를 통해서 스프링에서 해주는 많은 일들이 무엇이었나를 잘 알 수 있다. 내가 직접 만든 save, findById 외에도 수많은 기본적인 CRUD 오퍼레이션들을 내부적으로 자동으로 구현해주는 것이다.
자동으로 해주는 작업들의 작동 원리 알아보기
그렇다면 extends JpaRepository<Post, Long> 를 통해서 뒷단에서 발생하는 작업들은 어떤 원리로 발생하는 것인지 알아보자. JPA를 사용하려면 @EnableJpaRepositories 를 사용해줘야하는데 스프링부트에서는 해당 어노테이션이 기본적으로 사용되고 있다. (그래서 지금까지 명시적으로 적어줄 필요가 없었던 것이다)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(JpaRepositoriesRegistrar.class)
public @interface EnableJpaRepositories {
여기서 JpaRepositoriesRegistrar 가 있는데, 이 어노테이션의 상속구조를 따라가다 보면 ImportBeanDefinitionRegistrar 라는 인터페이스를 상속하고 있음을 알 수 있다.
결국 여기서 org.springframework.data.jpa.repository.JpaRepository 를 상속하는 interface 를 repository 로 사용할 수 있도록 bean 으로 등록해주고, 기본적인 자원들을 내부적으로 만들어준다고 볼 수 있다.
이와 관련하여 더 자세한 사항은 Spring Data Common 에서 살펴본다.
JPA 사용하여 개발할때 가져야 할 습관
JPA를 사용한다는 것은 곧 의도적으로 직접 사용하지 않는 이상 쿼리를 직접 만들어서 수행요청하지 않는다는 것이다. 즉, 자동 생성된 쿼리가 수행된다는 의미이다.
따라서 필연적으로 의도치 않게 성능에 오히려 마이너스가 되는 형태로 쿼리가 생성되고 수행 요청이 될 수 있다. 그렇기 때문에 JPA를 사용한다면 항상 로그를 통해서 개발한 로직에서 의도한 방식으로 적절하게 쿼리가 생성되고, 수행요청 되는지를 확인하면서 개발을 진행하여야 한다.
반드시 이러한 원칙을 가지고 JPA 를 사용해야 한다.
이를 위한 프로퍼티 설정은 아래를 참고하자.
spring:
datasource:
url: jdbc:mysql://localhost:3306/fistkim
username: root
password: root
jpa:
hibernate:
ddl-auto: create
show-sql: true <--- sql visible
properties:
hibernate:
format_sql: true <--- sql format
logging:
level:
org.hibernate.type.descriptor.sql: trace <--- 수행되는 sql의 값 visible
JPA 를 이용한 개발을 할 때에는 반드시 발생하는 모든 쿼리를 로그를 통해 직접 확인한다.