본문 바로가기
카테고리 없음

스프링 부트 핵심 가이드 3주차

by 이두덩이 2023. 8. 6.

 

 

▶ 제 06장.  데이터베이스 연동

1. ORM (Object Relational Mapping)

  • 객체와 RDB(Relational Database)의 테이블을 자동으로 매핑하는 방법
  • 쿼리문 작성이 아닌 코드(메서드)로 데이터를 조작 할 수 있음
  • 애플리케이션의 객체 관점과 DB의 관계 관점의 불일치
    • 세분성 : 클래스가 테이블의 수보다 많아질 수 있음
    • 상속성 : RDBMS에는 상속이라는 개념이 없음
    • 식별성 : RDBMS는 기본키로 동일성을 정의하지만 자바는 두 객체의 값이 같아도 다르다고 판단 할 수 있음
    • 연관성 : 객체지향에서는 객체 참조시 방향성 존재하지만 RDBMS에서 외래키를 삽입하는 것은 양방향의 관계를 갖음
    • 탐색 : 자바에서는 값에 접근을 위해 그래프 형태(예. member.getOrganization().getAddress()와 같이 접근)의 접근법을 사용하지만 RDBMS에서는 쿼리를 최소화하고 JOIN을 통해 여러 테이블을 로드하고 값을 추출함

2. JPA (Java Persistence API)

  • Java ORM 기술의 표준 인터페이스의 모음 -> 인터페이스이기 때문에 구현체는 존재하지 않음
  • 내부적으로 JDBC를 사용하지만 개발자가 대신 SQL을 생성하고 DB를 조작해서 객체를 자동 매핑하는 역할을 수행

3. 하이버네이트 (Hibernate)

  • 자바의 ORM 프레임워크로, JPA의 구현체
  • Spring Data JPA : 하이버네이트의 기능을 더욱 편하게 사용하도록 모듈화 한 스프링 하위 프로젝트 중 하나

4. 영속성 컨텍스트 (Persistence Context)

  • 엔티티 객체의 매핑 정보를 DB에 반영하는 작업을 수행 -> 엔티티와 테이블의 괴리를 해소, 객체 보관

5. 데이터 베이스 연동(application.yml파일 설정)

  • ddl-auto(운영환경 : validate, none 사용 / 개발환경 : create, update 사용)
    1. create : 애플리케이션 가동 후 SessionFactory가 실행될 때마다 기존 테이블을 지우고 다시 생성
    2. create-drop : create와 동일한 기능을 수행하지만 애플리케이션 종료시 테이블 삭제
    3. update : SessionFactory가 실행될 때 객체의 변경이 감지된 스키마만을 갱신
    4. validate : update처럼 객체를 검사하지만 스키마는 건드리지 않고 DB의 테이블 정보와 객체 정보가 다르면 에러 발생
    5. none : ddl-auto기능을 사용하지 않음

6. 엔티티 설계

  • Spring Data JPA를 사용하면 DB에 테이블 작성없이 엔티티 객체를 생성하고 실행을 돌리면 됨
  • 엔티티 관련 기본 어노테이션
    • @Entity 
      1. 해당클래스가 엔티티임을 명시
      2. 클래스 자체가 테이블과 일대일로 매핑
    • @Table
      1. 클래스명과 테이블 이름을 다르게 지정하고 싶을 때 사용
      2. 대체로 DB와 자바의 명명법이 다르기 때문에 거의 사용
    • @Id
      1. 테이블의 기본값 역할로 사용
      2. 모든 엔티티는 @Id어노테이션이 필요
    • @GeneratedValue
      1. @Id어노테이션과 함께 사용
      2. 해당 필드의 값을 어떤 방식으로 자동으로 생성할지 결정
        1. 사용하지 않는 방식
          • 애플리케이션에서 자체적으로 고유한 기본값을 생성하는 경우
          • 내부에 정해진 규칙에 의해 기본값을 생성하고 식별자로 사용
        2.  AUTO
          • @GeneratedValue의 기본 설정값
          • 기본값을 사용하는 DB에 맞게 자동 생성
        3. IDENTITY
          • 기본값 생성을 DB에 위임하는 방식
          • DB의 AUTO_INCREMENT를 사용해 기본값을 생성
        4. SEQUENCE
          • @SequenceGenerator 어노테이션으로 식별자 생성기를 설정하고 이를 통해 자동 주입 받음
          • SequenceCenertor를 정의할 때는 name, SequenceName, allocationSize를 활용
          • @GeneratedValue에 생성기를 설정
        5. TABLE
          • 어떤 DBMS를 사용하더라도 동일하게 동작하기를 원할 경우 사용
          • 식별자로 사용할 숫자의 보관 테이블을 별도로 생성해서 엔티티를 생성할 쌔마다 값을 생신하며 사용
          • @TableGenerator 어노테이션으로 테이블 정보를 설정
    • @Column(자주 사용하는 것들)
      1. name : DB의 칼럼명을 설정
      2. nullable : 레코드를 생성할 때 칼럼 값에 null 처리가 가능한지를 명시
      3. length : DB에 저장하는 데이터의 최대 길이를 설정
      4. unique : 해당 칼럼을 유니크로 설정
    • @Transient
      1. 엔티티 클래스에는 선언되어 있지는 필드 이지만 DB에서 필요 없는 경우

7. 리포지토리 인터페이스 설계

  • JpaRepository를 상속 받아서 사용
    • 예) public interface ProductRepository extends JpaRepository<Product, Long> {}
    • 대상 엔티티와 기본값 타입을 지정
  • 리포지토리 메서드의 생성 규칙
    • FindBy : SQL문의 where절 역할을 수행하는 구문, findBy 뒤에 엔티티의 필드값을 입력해 사용 예)findByName(String name)
    • AND, OR : 조건을 여러 개 설정하기 위해 사용 예) findByNameAndEmail(String name, String email)
    • Like/NotLike : SQL문의 like와 동일한 기능을 수행하며 특정 문자를 포함하는지 여부를 조건으로 추가, 비슷한 키워드로 Containing, Contains, isContaing이 있음.
    • StartsWith/StartngWith : 특정 키워드로 시작하는 문자열 조건을 설정
    • EndsWith/EndingWith : 특정 키워드로 끝나는 문자열 조건을 설정
    • IsNull/IsNotNull : 레코드 값이 Null이거나 Null이 아닌 값을 검색
    • True/False : Boolean 타입의 레코드를 검색할 때 사용
    • Before/After : 시간을 기준으로 값을 검색
    • LessThan/GreaterThan : 특정 값(숫자)를 기준으로 대소 비교를 할 때 사용
    • Between : 두 값(숫자) 사이의 데이터를 조회
    • OrderBy : SQL문에서 order by와 동일한 기능을 수행 예)List<Product> findByNameOrderByPriceAsc(String name)
    • countBy : SQL문의 count와 동일한 기능을 수행하며, 결과값의 개수(count)를 추출

8. DAO 설계

  • DB에 접근하기 위한 로직을 관리하기 위한 객체(Spring Data API에서는 Repository가 대체)
  • DAO 구현체 예제
    • insert : productRepository.save(product);
    • select
      1. productRepository.getById(number);
        • EntityManager의 getReference()메서드를 호출 -> 프락시 객체를 리턴
        • 실제로 쿼리는 프락시 객체를 통해 최초로 데이터에 접근하는 시점에 실행
        • 객체 존재 하지 않을 경우 EntityNotFoundException발생
        • findById보다 성능과 Optional객체에 대한 처리가 필요 없어 개발에 용이
      2. productRepository.findById(number);
        • EntityManager의 find()메서드를 호출
        • 영속성 컨텍스트의 캐시에서 값을 조회 -> 캐시에 없으면 DB 조회
        • 객체 존재하지 않을 경우 리턴 값으로 Optional객체 전달
        • Null값에 따른 처리를 하고 싶을 때 용이
    • update : find()를 통해 해당 객체를 영속성 컨텍스트의 캐시에 추가하고 set()을 통해 객체에 변경을 주면 변경을 감지해서 값을 변경하고 다시 save()를 통해 값이 갱신됨.
    • delete : update처럼 삭제하고자 하는 객체가 영속성 컨텍스트에 가져와야 하기 때문에 find()후에 delete()메서드롤 통하여 삭제