- 강의
- 102강(스프링 부트와 JPA v1) ~ 103강* 스프링 부트와 JPA v2)
JPA
- 기본 SQL 사용 구문의 불편한 점
- rowMapper 사용, 비슷한 SQL문 직접 작성
- 발생 원인
- SQL → 데이터 지향, 관계 지향, 선언적
- Java → 객체 지향적, 행위 지향 패러다임
- 해결방법 : ORM
ORM
- Object-Relation-Mapping
- 객체지향 언어와 RDB 변환을 자동으로 처리하는 기술
- 기존 entity의 간접 매핑 → "테이블 영속화" 변경
- 기술 적용
- Python → django ORM, SQLAlchemy
- Node.js → Sequelize.js
- Java → JPA
JPA
- Java Persistence API(JPA) → Java ORM 규약
- 장점
- 객체 지향 실현 가능
- 재사용 용이
- 코드 생산성 향상
- 단점
- 복잡한 요구에 대한 JPA 한계
- 초반/고급 러닝커브 ↑
- 내부 동작 원리
- JPA는 내부에 JDBC를 사용
- 구성요소
- Entity Transaction
- Entity Manager
- Query
- Persistence
- Entity Manager Factory
- 구현체
- Hibernate
- EclipsLink
- OpenJPA
Hibernate
- 장점
- 가장 널리 사용됨
- 완벽한 JPA 지원
- 다양한 성능 최적화 기능 제공
- 설정
- gradle 의존성 추가
- implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
- implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
- application.yml 로그 설정
- logging:
config: classpath:logback-spring-local.xml
level:
org:
hibernate:
SQL: DEBUG
- logging:
- JPA 관련 bean 등록(entity manager, transaction manager)
- gradle 의존성 추가
package com.github.supercodingspring.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableJpaRepositories(
basePackages = {"com.github.supercodingspring.repository.items", "com.github.supercodingspring.repository.storeSales"},
entityManagerFactoryRef = "entityManagerFactoryBean1",
transactionManagerRef = "tmJpa1"
)
public class JpaConfig1 {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean1(@Qualifier("dataSource1")DataSource dataSource){
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.github.supercodingspring.repository.items", "com.github.supercodingspring.repository.storeSales");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
properties.put("hibernate.format_sql", "true");
properties.put("hibernate.use_sql_comment", "true");
em.setJpaPropertyMap(properties);
return em;
}
@Bean(name = "tmJpa1")
public PlatformTransactionManager transactionManager1(@Qualifier("dataSource1") DataSource dataSource){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean1(dataSource).getObject());
return transactionManager;
}
}
- JPA Entity 만들기
- @Entity
- @Table(name = "실제 DB 테이블명") : 사용하지 않으면 클래스명을 entity 이름으로 함
- @Column : 컬럼
- JPA Repository 기본 메서드 사용하기
- extends JpaRepository<entity, id_type>
- 기초 CRD 제공
- save, findById, delete 등
- entity 업데이트 : 더티 체킹
- 자동 쿼리 메서드
- pagination 구현
// 페이지네이션
// request
http://localhost:8080/api/items-page?size=10&page=0
// controller
@ApiOperation("pagination 지원")
@GetMapping("/items-page")
public Page<Item> findItemsPagination(Pageable pageable){
return electronicStoreItemService.findAllWithPageable(pageable);
}
// service
public Page<Item> findAllWithPageable(Pageable pageable) {
Page<ItemEntity> itemEntities = electronicStoreItemJpaRepository.findAll(pageable);
return itemEntities.map(ItemMapper.INSTANCE::itemEntityToItem);
}
// repository
@Repository
public interface ElectronicStoreItemJpaRepository extends JpaRepository<ItemEntity, Integer> {
List<ItemEntity> findItemEntitiesByTypeIn(List<String> types);
List<ItemEntity> findItemEntitiesByPriceLessThanEqualOrderByPriceAsc(Integer maxValue);
Page<ItemEntity> findAllByTypeIn(List<String> types, Pageable pageable);
}
관계 매핑
- 고려사항
- 관계의 다중성
- 관계의 방향
- 관계의 주인
- 단방향
- 1:N 관계
- 1) N의 객체에 @ManyToOne, @JoinColumn을 선언하고, 1인 객체에 필드 X
- 2) 1의 객체에 @OneToMany, @JoinColumn 을 선언하고, N인 객체에 필드 X
- 1:1 관계
- @OneToOne , @JoinColumn
- N:M 관계
- 매핑하는 연결 테이블 생성
- 1:N 관계
- 다방향
- @ManyToOne, @JoinColumn
- @OneToMany
- 연관 관계 객체 가져오기
- Lazy(Fetch.Lazy) → 권장
- 2번의 select문을 통해서 가져옴
- 실제로 연관객체를 사용할 때 가져옴(실제로 필요할 때 사용)
- Eager(Fetch.Eager)
- Join문을 이용해서 가져옴 → 객체 조회 시 연관객체까지 가져옴
- Lazy(Fetch.Lazy) → 권장
JPQL
- Java Persistance Query Language → JPA의 객체지향 쿼리
- @Query 이용
대표적인 JPA 문제 : N+1 문제
- 연관 관계 설정된 Entity 조회 시, 조회된 갯수 만큼 조회 쿼리가 추가로 실행되는 현상
- 해결방법
- 1) Fetch.Eager 사용 → 항상 해결되는 것은 아님
- 2) JPQL 이용 : Fetch JOIN 이용
PSA
- Portable service Abstraction, 휴대용 서비스 추상화
- 특징
- 특정 기술에 접근하지 않고, 추상화를 통해서 코드 이식성, 유연성 ↑
- 이유(+예시)
- DB마다 문법이 다름
- JPA가 DB를 바꿀 경우, 코드의 변경이 필요함
- => JPQL Dialect가 DB에 따라서 기술 변경
- 특정 기술에 얽매이지 않는 코드 철학
'슈퍼코딩 > 주특기(JAVA)' 카테고리의 다른 글
2024.06.06(목) 슈퍼코딩 신입연수원 10주차 Day 4 후기 - Cache, Cookie & Session & JWT (1) | 2024.06.06 |
---|---|
2024.06.05(수) 슈퍼코딩 신입연수원 10주차 Day 3 후기 - 테스팅, 서버 업무, 서블릿 컨테이너, filter, interceptor (0) | 2024.06.05 |
2024.06.03(월) 슈퍼코딩 신입연수원 10주차 Day 1 후기 - 예외 처리, AOP (0) | 2024.06.03 |
슈퍼코딩 신입연수원 9주차 후기 (0) | 2024.06.01 |
2024.05.31(금) 슈퍼코딩 신입연수원 9주차 Day 5 후기 - Lombok, Mapper, 로깅, 문서화 (0) | 2024.05.31 |