JPA (Java Persistence API)
Java로 RDBMS에 접근하기 위해 필요한 기능을 제공하는 ORM 기술이다.
JPA는 POJO를 기반으로 작동한다. 따라서 객체지향 프로그래밍의 장점을 살리면서 데이터베이스 작업을 수행할 수 있다는 장점이 있다.
JPA는 표준 인터페이스로서 이를 실제 사용하기 위해서는 구현체가 필요하다.
대표적인 구현체는 Hibernate
, EcplipseLink
, OpenJPA
등이 있다.
ORM (Object Relational Mapping)
- SQL 작성 시 객체를 데이터베이스에 직접 접근할 수 있게 해주는 툴이다.
- SQL 문법 대신 애플리케이션의 개발 언어를 그대로 사용할 수 있게 하여 개발 언어의 일관성과 가독성을 높여준다.
- 직접 SQL문을 작성해야 했던 JDBC, MyBatis와 달리, JPA는 JDBC를 호출하여 SQL 쿼리를 실행한다. (이때 JPA는 객체 지향 쿼리 언어인 JPQL을 실행한다.) 따라서 개발자는 SQL에서 발생한 오류를 처리하는 대신 코드 품질과 테스트에 더 많은 시간을 사용할 수 있게 되었다.
id
, 이름
, 나이
)public class PersonSaveMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabegin"); //EntityManagerFactory 생성 EntityManager em = emf.createEntityManager(); //EntityManager 생성 EntityTransaction transaction = em.getTransaction(); //트랜잭션 생성 Person person = new Person("John", 25); //실제 데이터 try { transaction.begin(); em.persist(person); //Person 객체 영속화 transaction.commit(); } catch (Exception e) { transaction.rollback(); } finally { em.close(); } emf.close(); } }
EntityManagerFactory
와 EntityManager
은 데이터베이스에 접근하기 때문에 사용 후 자원을 닫아줘야 한다. 코드를 작성하다 보니 자원 해제 코드는 try-with-resources 문법을 적용하는 것이 가독성에 좋을 것 같아서 Autocloseable
을 구현하고 있는지 찾아보았다.public class PersonSaveMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabegin"); //EntityManagerFactory 생성 EntityManager em = emf.createEntityManager(); //EntityManager 생성 EntityTransaction transaction = em.getTransaction(); //트랜잭션 생성 Person person = new Person("John", 25); //실제 데이터 try(emf; em) { transaction.begin(); em.persist(person); //Person 객체 영속화 transaction.commit(); } catch (Exception e) { transaction.rollback(); } } }
Spring Data JPA
Spring 프레임워크에서 JPA을 간편하게 사용할 수 있도록 하는 라이브러리이다.
Spring Data JPA에서는 스프링 데이터 저장소를 추상화 한 Repository
라는 중앙 인터페이스를 통해 데이터 엑세스를 간단하게 처리할 수 있도록 한다.
CRUD, 쿼리 메서드, 페이징, 정렬 등의 기본적인 기능을 제공하여 개발자의 작업 효율성을 높여준다. 단, 동적 쿼리, 프로시저 등의 복잡한 쿼리를 작성하기에는 한계가 있어 이때는 Querydsl
, Criteria API
등을 함께 활용하는 것이 좋다.
@NoRepositoryBean을 제외한 Spring Data JPA Repository 인터페이스는 다음과 같다.
JpaRepository<T, ID>
를 extends 하여 사용한다. 그리하여 기본 CRUD(CrudRepository)
, 페이징과 정렬(PagingAndSortingRepository)
, 리스트 반환(List~)
기능을 사용할 수 있는 것이고, 그 외의 쿼리 메서드는 Custom Repository에 정의하여 사용할 수 있다. (참고로 SimpleJpaRepository
는 JpaRepository를 구현한 클래스이다.)@Transactional public void saveProduct(ProductSaveDto productSaveDto, Member member) { productRepository.save(Product.builder() .name(productSaveDto.getName()) .price(productSaveDto.getPrice()) .quantity(productSaveDto.getQuantity()) .manufacturer(productSaveDto.getManufacturer()) .member(member) .regDate(LocalDateTime.now()) .build()); }
@Transactional(readOnly = true) public Product findProduct(Long productId) { return productRepository.findById(productId).orElseThrow(() -> new IllegalArgumentException("잘못된 id 값입니다.")); }
Spring Data JPA
가 JPA
보다 좋다?그렇지 않다.
Spring Data JPA는 Repository를 상속하여 데이터 접근을 간편하게 만들어주지만, 복잡한 쿼리를 작성해야 할 경우 자동으로 생성된 쿼리가 최적화되지 않을 수 있다. 또한, Spring 프레임워크에 의존하기 때문에 POJO를 유지하는 데 제약이 있을 수 있다. 따라서 두 기술의 장단점을 명확히 파악하고, 상황에 맞게 적절히 사용할 필요가 있다.
참고