일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- designpatterns
- storybook
- RTK
- Gin
- golang
- hook
- frontend
- JPA
- javascript
- css
- springboot
- test
- component
- 티스토리챌린지
- Redux
- React
- Chakra
- tanstackquery
- go
- java
- backend
- react-hook-form
- 오블완
- ReactHooks
- satisfiles
- JavaSpring
- typescript
- Spring
- 웹애플리케이션서버
- Today
- Total
bkdragon's log
JPA와 하이버네이트 본문
하이버네이트(Hibernate)와 JPA(Java Persistence API)는 자바 애플리케이션에서 데이터베이스와 상호작용하기 위한 ORM(Object-Relational Mapping) 기술이다. 이 두 가지는 서로 밀접하게 관련되어 있지만, 약간의 차이가 있다.
JPA (Java Persistence API)
- 표준 인터페이스: JPA는 자바에서 ORM을 위한 표준 인터페이스를 제공한다. 즉, 특정 구현체에 종속되지 않고, 다양한 ORM 프레임워크에서 사용할 수 있는 공통 API를 정의한다.
- POJO 기반: JPA는 일반 자바 객체(POJO)를 데이터베이스 테이블에 매핑한다.
- 주요 기능: 엔티티 관리, 트랜잭션 관리, 쿼리 언어(JPQL) 등을 제공한다.
하이버네이트 (Hibernate)
- JPA 구현체: 하이버네이트는 JPA의 구현체 중 하나로, JPA의 표준을 따르면서도 추가적인 기능을 제공한다.
- 고급 기능: 캐싱, 배치 처리, 고급 쿼리 기능 등 JPA 표준에 포함되지 않은 다양한 기능을 제공한다. (뒤에 추가 설명)
- 확장성: 하이버네이트는 다양한 데이터베이스를 지원하며, 복잡한 데이터베이스 구조를 쉽게 관리할 수 있도록 돕는다.
인터페이스와 구현체 사용의 이유
유연성: 인터페이스를 사용하면 구현체를 쉽게 교체할 수 있다. 이는 코드의 유연성을 높이고, 특정 구현체에 종속되지 않도록 한다.
// 인터페이스 정의 public interface PaymentService { void processPayment(double amount); } // 구현체 1 public class CreditCardPaymentService implements PaymentService { public void processPayment(double amount) { System.out.println("Processing credit card payment of " + amount); } } // 구현체 2 public class PayPalPaymentService implements PaymentService { public void processPayment(double amount) { System.out.println("Processing PayPal payment of " + amount); } } // 사용 예시 PaymentService paymentService = new CreditCardPaymentService(); paymentService.processPayment(100.0);
유지보수성: 인터페이스를 통해 코드를 모듈화하면, 각 모듈을 독립적으로 개발하고 유지보수할 수 있다.
// 인터페이스 정의 public interface Logger { void log(String message); } // 파일 로거 구현체 public class FileLogger implements Logger { public void log(String message) { // 파일에 로그 작성 System.out.println("Logging to file: " + message); } } // 콘솔 로거 구현체 public class ConsoleLogger implements Logger { public void log(String message) { System.out.println("Logging to console: " + message); } } // 사용 예시 Logger logger = new ConsoleLogger(); logger.log("Application started");
테스트 용이성: 인터페이스를 사용하면 모의 객체(Mock Object)를 활용하여 테스트를 쉽게 수행할 수 있다. 특히, 데이터베이스와 상호작용하는 레포지토리를 모킹하여 테스트할 수 있다.
import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; @SpringBootTest public class UserRepositoryTest { @MockBean private UserRepository userRepository; // 모의 객체 주입 @Test public void testFindById() { // Given User mockUser = new User(1L, "Mock User"); given(userRepository.findById(1L)).willReturn(mockUser); // When User foundUser = userRepository.findById(1L); // Then assertNotNull(foundUser); assertEquals("Mock User", foundUser.getName()); verify(userRepository).findById(1L); } @Test public void testSave() { // Given User user = new User(2L, "Another User"); // When userRepository.save(user); // Then verify(userRepository).save(user); } }
표준화: 인터페이스는 표준화된 방법으로 기능을 정의하여, 다양한 구현체가 동일한 방식으로 동작하도록 보장한다. 예를 들어, 도형의 면적을 계산하는 기능을 표준화할 수 있다.
// 인터페이스 정의 public interface Shape { double area(); } // 원 구현체 public class Circle implements Shape { private double radius; public Circle(double radius) { this.radius = radius; } public double area() { return Math.PI * radius * radius; } } // 사각형 구현체 public class Rectangle implements Shape { private double width, height; public Rectangle(double width, double height) { this.width = width; this.height = height; } public double area() { return width * height; } } // 사용 예시 Shape circle = new Circle(5); Shape rectangle = new Rectangle(4, 6); System.out.println("Circle area: " + circle.area()); System.out.println("Rectangle area: " + rectangle.area());
하이버네이트의 JPA 인터페이스 구현 예시
EntityManager: JPA의 핵심 인터페이스 중 하나인
EntityManager
는 엔티티의 생명주기를 관리한다. 하이버네이트는 이를Session
인터페이스로 구현하여, 데이터베이스와의 세션을 관리하고, 엔티티의 저장, 삭제, 업데이트 등의 작업을 수행한다.// 하이버네이트 Session을 사용하여 엔티티를 관리하는 예시 SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = null; try { transaction = session.beginTransaction(); // 엔티티 저장 MyEntity entity = new MyEntity(); entity.setName("Example"); session.save(entity); // 엔티티 조회 MyEntity retrievedEntity = session.get(MyEntity.class, entity.getId()); // 엔티티 업데이트 retrievedEntity.setName("Updated Example"); session.update(retrievedEntity); // 엔티티 삭제 session.delete(retrievedEntity); transaction.commit(); } catch (Exception e) { if (transaction != null) { transaction.rollback(); } e.printStackTrace(); } finally { session.close(); }
하이버네이트의 고급 기능
하이버네이트는 JPA 표준에 포함되지 않은 다양한 고급 기능을 제공하여 개발자에게 더 많은 선택지를 제공한다.
캐싱: 하이버네이트는 1차 캐시와 2차 캐시를 지원한다. 1차 캐시는 세션 범위 내에서 작동하며, 동일한 세션 내에서 동일한 엔티티를 여러 번 조회할 때 데이터베이스에 불필요한 쿼리를 보내지 않는다. 2차 캐시는 세션 팩토리 범위에서 작동하며, 여러 세션 간에 데이터를 공유할 수 있다. 이를 통해 데이터베이스 부하를 줄이고 성능을 향상시킬 수 있다.
// 2차 캐시 설정 예시 @Entity @Cacheable @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class Product { @Id private Long id; private String name; // 기타 필드 및 메서드 }
배치 처리: 하이버네이트는 대량의 데이터를 효율적으로 처리하기 위한 배치 처리 기능을 제공한다. 이를 통해 여러 SQL 명령을 하나의 배치로 묶어 데이터베이스에 전송하여 성능을 최적화할 수 있다.
// 배치 처리 예시 Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); for (int i = 0; i < 1000; i++) { Product product = new Product(); product.setName("Product " + i); session.save(product); if (i % 50 == 0) { // 50개마다 배치 처리 session.flush(); session.clear(); } } transaction.commit(); session.close();
JPA와 하이버네이트의 차이점 정리
특징 | JPA | 하이버네이트 |
---|---|---|
표준화 | 표준 인터페이스로 다양한 구현체와 호환 가능 | JPA 표준을 따르면서도 추가 기능 제공 |
유연성 | 특정 구현체에 종속되지 않음 | 다양한 데이터베이스와 복잡한 구조 지원 |
기능성 | 기본적인 ORM 기능 제공 | 캐싱, 배치 처리, 고급 쿼리 등 추가 기능 제공 |
성능 | 기본적인 성능 제공 | 캐싱 및 배치 처리로 성능 최적화 가능 |
'Java Spring' 카테고리의 다른 글
웹 기술의 발전과정 (0) | 2024.11.12 |
---|---|
Specification 과 Criteria API (0) | 2024.11.08 |
Transactional 원리 (0) | 2024.09.24 |
JDBC 부터 Spring Data JPA 까지 (0) | 2024.09.20 |