https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-jpa
ㅁ 관계형 데이터베이스와 자바
- Hibernate는 JPA의 구현체이다.
- docker 기반 postgresql 사용
# docker run -p 5432:5432 -e POSTGRES_PASSWORD=pass -e POSTGRES_USER=defian -e POSTGRES_DB=springdata --name postgres_boot -d postgres
- 문제 발생 및 해결 (psql: error: FATAL: role "postgres" does not exist)
root@452fe3e3c1de:/# su - postgres
postgres@452fe3e3c1de:~$ psql springdata
psql: error: FATAL: role "postgres" does not exist
postgres@452fe3e3c1de:~$
postgres@452fe3e3c1de:~$ psql --username defian --dbname springdata
psql (13.3 (Debian 13.3-1.pgdg100+1))
Type "help" for help.
springdata=#
- jdbc는 자바에 기본적으로 포함되어 있음
- DDL : 스키마 조작 / DML : 데이터 조작
- statement와 connection은 try로 감싸서 자원 반환하기 용이하게 함 (try with resource 문이라 부름 - 자바 8부터 가능)
- 커넥션을 만드는 일이 코스트가 많이 드는 일임 (오래걸림)
> 커넥션 풀을 만들어 사용하는게 유용함 (오픈소스가 많음 - spring은 hikari 라는 오픈소스 사용 )
- SQL이 DB마다 다르고 반복적인 소스코드가 많음
ㅁ ORM : Object-Relation Mapping
- ORM은 애플리케이션의 클래스와 SQL 데이터 베이스의 테이블 사이의 맵핑 정보를 기술한 메타데이터를 사용하여, 자바 애플리케이션의 객체를 SQL 데이터베이스의 테이블에 자동으로 ( 또 깨끗하게 ) 영속화 해주는 기술입니다.
- ORM, JPA, Hibernate 에서는 DB와 코드 사이에 캐싱이 있어서, 객체의 변화를 확인하여 실제 변경해야될 경우에만 쿼리를 발생 시킴
- Hibernate, ORM은 러닝커브가 높다.
ㅁ ORM 패러다임 불일치
- 밀도 문제 : 커스텀한 타입에 대한 관계 문제를 ORM이 해결해줌
- 서브타입 문제 : interface에 대해 2개의 구현체가 있을때, 이것들의 interface 를 값으로 같는 객체를 어떻게 테이블로 구현할 것인가?
- 식별성 문제 : 객체는 ==, equals 로 비교, 테이블은 primary key로 비교
- 관계 문제 : 객체는 다대다 관계가 가능하나, 테이블은 어려움
- 데이터 네비게이션 문제 : 쿼리를 만들고 실행하는 비용은 비싸다. join을 많이 발생시키는것도 좋은것은 아님
> n+1 문제 : lazyloading 시 발생, 전체 조회 + 한줄씩 조회
ㅁ JPA 프로그래밍
- JPA와 Hibernate API 를 직접 사용하는 일은 거의 없다.
> Spring data JPA 사용
- EntityManager가 핵심적인 객체이다
@PersistenceContext
EntityManager entityManager;
entityManager.persist(account);
- session을 통해서도 가능
Session session = entityManager.unwrap(Session.class);
session.save(account);
- @Entity (name="myAccount") 로 엔티티 이름 생성
@Table에서 @Entity의 이름과 동일하게 테이블 생성 (없으면 class 네임씀 )
> user와 같이 db 에 존재하는 설정 테이블일 경우, class 이름 = user , @entity 로 생성 불가능
=> entity 이름을 바꾸면 됨
- @Id의 경우, premitive와 reference 타입 모두 가능
-> 보통 refernece를 씀 ( null 로 구분 지을 수 있음)
- @GenerateValue로 생성되는 id 값의 전략 설정 가능 (DB 마다 다름 )
- 모든 entity에 들어있는 멤버변수는 @Column이 생략되어있음
> columnDefinition을 써서 매핑도 가능
> columnDefinition(nullable=false, unique = true) 로 설정
- @Temporal로 date와 calendar 지원 (jpa 2.1)
- @Transient는 맵핑하지 않게함
- getter setter는 필요없음
- Compositive 한 value 타입 만들기
> 객체 (address) 생성 후, @Embeddable 추가
>아래와 같이 추가
@Embedded
@AttributeOverrides({
@AttributeOverride(name="street", column=@Column(name="home_street"))
})
private Address homeAddress;
>> 테이블에는 address 객체가 가진 column이 들어감
- @ManyToOne 이 헷갈릴경우,
이 어노테이션 단 곳이 one인지 many인지 생각
> DB에 foreignkey 칼럼이 새로 생김
- 양방향 관계일때는 @OneToMany에 mapped by로 반대쪽 관계를 설정해준다.
> 양쪽에 서로를 등록시켜주는게 객체지향 및 방향성에 맞는 코딩
- 1차 캐시 : 이미 있는건 select 하지 않음
dirty checking : 객체의 변경사항을 계속 감시
write behind: 최대한 늦게 객체를 업데이트함
=> 캐싱까지 하여, 여러번 객체가 바뀌더라도 한번만 update , insert 진행
- repository에서 service로 넘기면 detached 상태가 되어 더이상 관리하지 않음
(transaction과 관련있음 )
- Cascade는 부모 엔티티가 persistent 면 child 엔티티도 persistent 상태로 만들음
> 자동으로 JPA가 관리하게 해줌 (부모가 삭제되면 child도 삭제되는 등.. post 와 comment 관계 )
- Fetch : 연관된 엔티티를 어떻게 가져올 것이냐 (지금 : eager / 나중에 : lazy)
> eager를 통해 한번 호출하여, 두번 호출하지 않게함
> 성능향상에 중요함
- session은 hibernate에 있는 api이고, EntityManager를 통해 unwrap하여 jpa가 감싸고 있는 hibernate api에 접속해서 썼던것
> entitymanager의 persist 등을 통해 비슷한 기능을 하게 할 수 있음
- 쿼리 하는 방법은?
Java Persistence Query Language / Hibernate Query Language
> entityManager.createQuery("SELECT p FROM post as p);
ㅁ 스프링 데이터 JPA 원리
- 아래 코드는 오래된 repository 생성 코드
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import java.util.List;
@Repository
@Transactional
public class PostRepository {
@PersistenceContext
EntityManager entityManager;
public Post add(Post post){
entityManager.persist(post);
return post;
}
public void delete(Post post){
entityManager.remove(post);
}
public List<Post> findAll(){
return entityManager.createQuery("SELECT p FROM Post AS p").getResultList();
}
}
- 가장 진보적인 repository 생성 코드
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostRepository extends JpaRepository<Post,Long> {
}
- JpaRepository의 첫번째는 Entity 타입, 두번째는 id 타입
- 스캐닝이나 등록 필요가 없음 ( 부트가 자동으로 해줌 )
- @EnableJpaRepositories 에서 위 repository를 등록이 시작됨
> ImportBeanDefinitionRegister 인터페이스
반드시 Hibernate가 발생시키는 Query를 확인하는 습관을 기르자. ( 이게 성능의 핵심 )
'Spring' 카테고리의 다른 글
[Spring] 스프링 데이터 JPA - 3 (0) | 2021.07.25 |
---|---|
[Spring] 스프링 데이터 JPA - 2 (0) | 2021.07.23 |
[Spring] 스프링 부트 업데이트 - 4 (0) | 2021.07.22 |
[Spring] 스프링 부트 업데이트 - 3 (0) | 2021.07.21 |
[Spring] 스프링 부트 업데이트 - 2 (0) | 2021.07.21 |