728x90
6.2 ORM
- Object Relational Mapping = 객체 관계 매핑
- 자바와 같은 객체지향 언어에서 의미하는 객체와 RDB(Relational Database)의 테이블을 자동으로 매핑하는 방법
- 객체 = 클래스
- 클래스는 데이터베이스의 테이블과 매핑하기 위해 만들어진 것이 아니기 때문에 RDB 테이블과 어쩔 수 없는 불일치가 존재함 → ORM은 이러한 불일치와 제약사항을 해결하는 역할
ORM의 장점
- ORM을 사용하면서 데이터베이스 쿼리를 객체지향적으로 조작할 수 있음
- 쿼리문을 작성하는 양이 현저히 줄어 개발 비용이 줄어듦
- 객체지향적으로 데이터베이스에 접근할 수 있어 코드의 가독성을 높임
- 재사용 및 유지보수가 편리함
- ORM을 통해 매핑된 객체는 모두 독립적으로 작성되어 있어 재사용이 용이함
- 객체들은 각 클래스로 나뉘어 있어 유지보수가 수월함
- 데이터베이스에 대한 종속성이 줄어듦
- ORM을 통해 자동 생성된 SQL문은 객체를 기반으로 데이터베이스 테이블을 관리하기 때문에 데이터베이스에 종속적이지 않음
- 데이터베이스를 교체하는 상황에서도 비교적 적은 리스크를 부담함
ORM의 단점
- ORM만으로 온전한 서비스를 구현하기에는 한계가 있음
- 복잡한 서비스의 경우 직접 쿼리를 구현하지 않고 코드로 구현하기 어려움
- 복잡한 쿼리를 정확한 설계 없이 ORM만으로 구성하게 되면 속도 저하 등의 성능 문제가 발생할 수 있음
- 애플리케이션의 객체 관점과 데이터베이스의 관계 관점의 불일치가 발생함
- 세분성(Granularity) : ORM의 자동 설계 방법에 따라 데이터베이스에 있는 테이블의 수와 애플리케이션의 엔티티 클래스의 수가다른 경우가 생김 (클래스가 테이블의 수보다 많아질 수 있음)
- 상속성(Inheritance) : RDBMS에는 상속이라는 개념이 없음
- 식별성(Identity) : RDBMS는 기본키로 동일성을 정의하는데 비해 자바는 두 객체의 값이 같아도 다르다고 판단할 수 있음 (식별과 동일성의 문제)
- 연관성(Associations) : 객체지향 언어는 객체를 참조함으로써 연관성을 나타내지만 RDBMS에서는 외래키를 삽입함으로써 연관성을 표현하며 객체지향 언어에서 객체를 참조할 때는 방향성이 존재하지만 RDBMS에서 외래키를 삽입하는 것은 양방향의 관계를 가지기 때문에 방향성이 없음
- 탐색(Navigation) : 자바와 RDBMS는 어떤 값(객체)에 접근하는 방식이 다름
- 자바에서는 특정 값에 접근하기 위해 객체 참조 같은 연결 수단을 활용하는데, 이 방식은 객체를 연결하고 또 연결해서 접근하는 그래프 형태의 접근 방식임
- RDBMS에서는 쿼리를 최소화하고 조인을 통해 여러 테이블을 로드하고 값을 추출하는 접근 방식을 채택함
6.3 JPA
- 자바 진영의 ORM 기술 표준으로 채택된 인터페이스의 모음
- ORM이 큰 개념이라면 JPA는 더 구체화된 스펙을 포함함
- 실제로 동작하는 것이 아닌, 어떻게 동작해야 하는지 메커니즘을 정리한 표준 명세
JPA는 내부적으로 JDBC를 사용한다.
개발자가 직접 JDBC를 구현하면 SAL에 의존하게 되는 문제 등이 있어 개발의 효율성이 떨어지는데, JPA는 이 같은 문제점을 보완해서 개발자 대신 적절한 SQL을 생성하고 데이터베이스를 조작해서 객체를 자동 매핑하는 역할을 수행한다.
대표적인 JPA 기반 구현체 3가지
6.4 하이버네이트
- 자바 ORM 프레임워크
- JPA가 정의하는 인터페이스를 구현하고 있는 JPA 구현체 중 하나
6.4.1 Spring Data JPA
- JPA를 편리하게사용할 수 있도록 지원하는 스프링 하위 프로젝트
- CRUD 처리에 필요한 인터페이스 제공
- 하이버네이트의 엔티티 매니저를 직접 다루지 않고 리포지토리를 정의해 사용함으로써스프링이 적합한 쿼리를 동적으로 생성하는 방식으로 데이터베이스를 조작함
6.5 영속성 컨텍스트
- 애플리케이션과 데이터베이스 사이에서엔티티와 레코드의 괴리를 해소하는 기능과 객체를 보관하는 기능을 수행
- 엔티티 객체가 영속성 컨텍스트에 들어오면 JPA는 엔티티 객체의 매핑 정보를 데이터베이스에 반영하는 작업을 수행
- 엔티티 객체가 영속성 컨텍스트에 들어와 JPA의 관리 대상이 되는 시점부터는 해당 객체를 영속 객체라고 부름
영속성 컨텍스트는세션 단위의 생명주기를 갖는다.
데이터베이스에 접근하기 위한 세션이 생성되면 영속성 컨텍스트가 만들어지고, 세션이 종료되면 영속성 컨텍스트도 없어진다.
엔티티 매니저는 이러한 일련의 과정에서 영속성 컨텍스트에 접근하기 위한 수단으로 사용된다.
6.5.1 엔티티 매니저
- 이름 그대로 엔티티를 관리하는 객체
- 데이터베이스에 접근하여 CRUD 작업 수행
- Spring Data JPA를 사용하면 리포지토리를 사용해서 데이터베이스에 접근
- 엔티티 매니저 팩토리에 의해 만들어짐
- 엔티티매니저 팩토리 : 데이터베이스에 대응하는 객체
6.5.2 엔티티의 생명주기
엔티티 객체의 4가지 상태
- 비영속(New) : 영속성 컨텍스트에 추가되지 않은 엔티티 객체의 상태
- 영속(Managed) : 영속성 컨텍스트에 의해 엔티티 객체가 관리되는 상태
- 준영속(Detached) : 영속성 컨텍스트에 의해 관리되던 엔티티 객체가 컨텍스트와 분리된 상태
- 삭제(Removed) : 데이터베이스에서 레코드를 삭제하기 위해 영속성 컨텍스트에 삭제 요청을 한 상태
6.7 엔티티 설계
6.7.1 엔티티 관련 기본 어노테이션
@Entity
- 해당 클래스가 엔티티임을 명시하기 위한 어노테이션
- 클래스 자체는 테이블과 일대일로 매칭되며, 해당 클래스의 인스턴스는 매핑되는 테이블에서 하나의 레코드를 의미함
@Table
- 엔티티 클래스는테이블과 매핑되므로 특별한 경우가 아니면 해당 어노테이션이 필요하지 않음
- 클래스의 이름과 테이블의 이름을 다르게 지정해야 하는 경우
@Id
- 엔티티 클래스의 필드는 테이블의 칼럼과 매핑됨
- @Id 어노테이션이 선언된 필드는 테이블의 기본값 역할로 사용됨
- 모든 엔티티는 @Id 어노테이션이 필요함
@GeneratedValue
- 일반적으로 @Id 어노테이션과 함께 사용됨
- 해당 필드의 값을어떤 방식으로자동으로 생성할지 결정할 때 사용됨
- 사용X (직접할당)
- 애플리케이션에서 자체적으로고유한 기본값을 생성할 경우 사용하는 방식
- 내부에 정해진 규칙에 의해 기본값을 생성하고 식별자로 사용함
- AUTO
- @GeneratedValue의 기본 설정값
- 기본값을 사용하는 데이터베이스에 맞게 자동 생성
- IDENTITY
- 기본값 생성을 데이터베이스에 위임
- AUTO_INCREMENT
- SEQUENCE
- @SequenceGenerator 어노테이션으로 식별자 생성기를 설정하고 이를 통해 값을 자동 주입 받음
- SequenceGenerator를 정의할 때는 name, sequenceName, allocationSize 활용
- @GeneratedValue에 생성기 설정
- TABLE
- 어떤 DBMS를 사용하더라도동일하게 동작하기를 원할 경우 사용
- 식별자로 사용할 숫자의 보관 테이블을 별도로 생성해서 엔티티를 생성할 때마다값을 갱신하며 사용
- @TableGenerator 어노테이션으로 테이블 정보 설정
- 사용X (직접할당)
@Column
엔티티 클래스의 필드는 자동으로 테이블 칼럼으로 매핑되기에 별다른 설정을 하지 않을 경우 해당 당어노테이션은 생략 가능하다.
- name : 데이터베이스의 칼럼명을 설정하는 속성, 명시하지 않으면 필드명으로 지정됨
- nullable : 레코드를 생성할 때 칼럼값에 null 처리가 가능한지를 명시하는 속성
- length : 데이터베이스에저장하는 데이터의 최대 길이 설정
- unique : 해당 칼럼을 유니크로 설정
@Transient
엔티티 클래스에는 선언돼 있는 필드지만 데이터베이스에서는 필요 없을 경우 이 어노테이션을 사용하여 데이터베이스에서 이용하지 않게 할 수 있다.
6.8 리포지토리 인터페이스 설계
Spring Data JPA는 JpaRepository를 기반으로 더욱 쉽게 데이터베이스를 사용할 수 있는 아키텍처를 제공한다.
스프링 부트로 JpaRepository를 상속하는 인터페이스를 생성하면 기존의 다양한 메서드를 손쉽게 활용할 수 있다.
6.8.1 리포지토리 인터페이스 생성
public interface ProductRepository extends JpaRepository<Product, Long> {
}
JpaRepository의 상속 구조
6.8.2 리포지토리 메서드의 생석 규칙
- FindBy : SQL문의where절 역할, findBy 뒤에 엔티티의 필드값을 입력해서 사용
- e.g. findByName(String name)
- AND, OR : 조건을 여러 개 설정하기 위해 사용
- e.g. findByNameAndEmail(String name, String email)
- Like/NotLike : SQL문의 like와 동일한 기능을 수행하며, 특정 문자를 포함하는지 여부를 조건으로 추가함 (비슷한 키워드 : Containing, Contains, isContaing)
- StartsWith/StartingWith : 특정 키워드로 시작하는 문자열 조건 설정
- EndsWith/EndingWith : 특정 키워드로 Rmxsk는 문자열 조건 설정
- IsNull/IsNotNull : 레코드의 값이 Null이거나 Null이 아닌 값을 검색
- True/False : Boolean 타입의 레코드 검색시 사용
- Before/After : 시간을 기준으로 값 검색
- LessThan/GreaterThan : 특정 값(숫자)을 기준으로 대소 비교
- Between : 두 값(숫자) 사이의 데이터 조회
- OrderBy : SQL문에서 order by와 동일한 기능 수행
- countBy : SQL문의 count와 동일한 기능 수행
6.9 DAO 설계
DAO
- Data Access Object
- 데이터베이스에 접근하기 위한 로직을 관리하기 위한 객체
- 리포지토리로 대체
'Spring > 스프링 부트 핵심 가이드' 카테고리의 다른 글
[Spring] Ch.5 API를 작성하는 다양한 방법 (0) | 2024.04.08 |
---|---|
[Spring] Ch.2 개발에 앞서 알면 좋은 기초 지식 (2) | 2024.03.24 |
[Spring] Ch.1 스프링 부트란? (1) | 2024.03.24 |