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 JPASpring 프레임워크에서 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를 유지하는 데 제약이 있을 수 있다. 따라서 두 기술의 장단점을 명확히 파악하고, 상황에 맞게 적절히 사용할 필요가 있다.
참고