5.1 데이터베이스
1. 데이터베이스 관리자, DBMS
DBMS(database management system) : 데이터베이스를 관리하기 위한 소프트웨어, 관계형
데이터베이스는 많은 사람이 공유할 수 있어야 하므로 동시 접근을 할 수 있어야 함.
- 관계형 DBMS (RDBMS)
: 테이블 형태로 이루어진 데이터 저장소
ex) H2 : 자바로 작성되어 있는 RDBMS, 스프링 부트가 지원하는 인메모리 관계형 데이터베이스, 애플리케이션 자체 내부에 데이터를 저장하는 특징, 그래서 애플리케이션을 다시 실행하면 데이터는 초기화 됨. 간편 사용, 개발 시에 테스트 용도로 많이 사용
(스프링 부트 3 백엔드 개발자 되기 책에서도 개발 시에는 H2, 실제 서비스로 올릴 때는 MySQL을 사용)
- 데이터베이스 용어
① 테이블 : 데이터베이스에서 데이터를 구성하기 위한 가장 기본적인 단위. 테이블은 행과 열로 구성됨. 행은 여러 속성으로 구성됨.
② 행 : 테이블의 가로로 배열된 데이터의 집합. 행은 반드시 고유한 식별자인 기본키를 가짐. 행을 레코드라고 부르기도 함
③ 열 : 행에 저장되는 유형의 데이터.
④ 기본키 : 행을 구분할 수 있는 식별자. 이 값은 테이블에서 유일해야 하며 중복 값을 가질 수 없음. 보통 데이터를 수정하거나 삭제하고, 조회할 때 사용되며 다른 테이블과 관계를 맺어 데이터를 가져올 수도 있음. 또한 기본키의 값은 수정되어서는 안 되며 유효한 값이어야 함. 즉 NULL이 될 수 없음.
⑤ 쿼리 : 데이터베이스에서 데이터를 조회하거나 삭제, 생성, 수정같은 처리를 하기 위해 사용하는 명령문. SQL이라는 데이터베이스 전용 언어를 사용하여 작성함
5.2 ORM
ORM(object-relational mapping) : 자바의 객체와 데이터베이스를 연결하는 프로그래밍 기법
ORM이 있다면 데이터베이스의 값을 마치 객체처럼 사용할 수 있음. SQL을 전혀 몰라도 자바 언어로만 데이터베이스에 접근해서 원하는 데이터를 받아올 수 있음. 즉 객체와 데이터베이스를 연결해 자바 언어로만 데이터베이스를 다룰 수 있게 하는 도구
5.3 JPA와 하이버네이트
자바에서는 JPA(ORM의 여러 종류 중 하나)를 표준으로 사용함.
JPA : 자바에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스
인터페이스이므로 실제 사용을 위해서는 ORM 프레임워크를 추가로 선택해야 함. 대표적으로 하이버네이트 많이 사용.
하이버네이트 : JPA 인터페이스를 구현한 구현체, 자바용 ORM 프레임워크, 내부적으로는 JDBC API를 사용함.
하이버네이트의 목표 : 자바 객체를 통해 데이터베이스 종류에 상관없이 데이터베이스를 자유자재로 사용할 수 있게 하는 데 있음.
** JPA와 하이버네이트의 역할 **
- JPA : 자바 객체와 데이터베이스를 연결해 데이터를 관리함. 객체 지향 도메인 모델과 데이터베이스의 다리 역할을 함.
- 하이버네이트 : JPA의 인터페이스를 구현함. 내부적으로는 JDBC API를 사용함
1. 엔티티 매니저
- 엔티티(entity)
: 데이터베이스의 테이블과 매핑되는 객체. 본질적으로는 자바 객체이므로 일반 객체와 다르지 않음.
하지만 데이터베이스의 테이블과 직접 연결된다는 특별한 특징이 있어 구분지어 부름. 즉 엔티티는 객체이긴 하지만 데이터베이스에 영향을 미치는 쿼리를 실행하는 객체
- 엔티티 매니저
: 엔티티를 관리해 데이터베이스와 어플리케이션 사이에서 객체를 생성, 수정, 삭제하는 등의 역할을 함.
이런 엔티티 매니저를 만드는 곳이 엔티티 매니저 팩토리
→ 스프링 부트는 내부에서 엔티티 매니저 팩토리를 하나만 생성해서 관리하고 @PersistenceContext, @Autowired 애너테이션을 사용해서 엔티티 매니저를 사용함.
ex)
@PersistenceContext
EntityManager em; // 프록시 엔티티 매니저. 필요할 때 진짜 엔티티 매니저 호출
스프링 부트는 기본적으로 빈은 하나만 생성해서 공유 → 동시성 문제가 발생할 수 있음
→ 실제로는 엔티티 매니저가 아닌 실제 엔티티 매니저와 연결하는 프록시(가짜) 엔티티 매니저를 사용
필요할 때 데이터베이스 트랜잭션과 관련된 실제 엔티티 매니저를 호출함
2. 영속성 컨텍스트
엔티티 매니저는 엔티티를 영속성 컨텍스트에 저장한다는 특징이 있음.
영속성 컨텍스트는 JPA의 중요한 특징 중 하나로, 엔티티를 관리하는 가상의 공간
→ 데이터베이스에서 효과적으로 데이터를 가져올 수 있고, 엔티티를 편하게 사용할 수 있음
- 영속성 컨텍스트의 특징
① 1차 캐시 : 영속성 컨텍스트는 내부에 1차 캐시를 가지고 있음. 이때 캐시의 키는 엔티티의 @Id 애너테이션이 달린 기본키 역할을 하는 식별자이며 값은 엔티티.
엔티티를 조회하면 1차 캐시에서 데이터를 조회
→ 값이 있으면 반환함. 값이 없으면 데이터베이스에서 조회해 1차 캐시에 저장한 다음 반환함.
→ 이를 통해 캐시된 데이터를 조회할 때에는 데이터베이스를 거치지 않아도 되므로 매우 빠르게 데이터를 조회할 수 있음.
② 쓰기 지연 : 트랜잭션을 커밋하기 전까지는 데이터베이스에 실제로 질의문을 보내지 않고 쿼리를 모았다가 트랜잭션을 커밋하면 모았던 쿼리를 한번에 실행하는 것
ex) 데이터 추가 쿼리가 3개라면 영속성 컨텍스트는 트랜잭션을 커밋하는 시점에 3개의 쿼리를 한꺼번에 쿼리를 전송함.
→ 적당한 묶음으로 쿼리를 요청할 수 있어 데이터베이스 시스템의 부담을 줄일 수 있음
③ 변경 감지 : 트랜잭션을 커밋하면 1차 캐시에 저장되어 있는 엔티티의 값과 현재 엔티티의 값을 비교해서 변경된 값이 있다면 변경 사항을 감지해 변경된 값을 데이터베이스에 자동으로 반영함.
→ 적당한 묶음으로 쿼리를 요청할 수 있고, 데이터베이스 시스템의 부담을 줄일 수 있음.
④ 지연 로딩 : 쿼리로 요청한 데이터를 애플리케이션에 바로 로딩하는 것이 아니라 필요할 때 쿼리를 날려 데이터를 조회하는 것
3. 엔티티의 상태
- 영속성 컨텍스트가 관리하고 있지 않는 분리 상태
- 영속성 컨텍스트가 관리하는 관리 상태
- 영속성 컨텍스트와 전혀 관계가 없는 비영속 상태
- 삭제된 상태
→ 상태는 특정 메서드를 호출해 변경할 수 있음, 필요에 따라 엔티티의 상태를 조절해 데이터를 올바르게 유지, 관리 가능
ex)
public class EntityManagetTest {
@Autowired
EntityManager em;
public void example() {
// 비영속 상태 : 엔티티 매니저가 엔티티를 관리하지 않는 상태
Member member = new Member(1L, "홍길동");
// 관리 상태
em.persist(member);
// 분리 상태
em.detach(member);
// 삭제 상태
em.remove(member);
}
}
- 엔티티를 처음 만들면 엔티티는 비영속 상태
- persist() 메서드 사용 → 엔티티를 관리 상태로 만들 수 있음, Member 객체는 영속성 컨텍스트에서 상태가 관리됨
- detach() 메서드 사용 → 분리 상태로
- remove() 메서드 사용 → 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제
5.4 스프링 데이터와 스프링 테이터 JPA
스프링 데이터 : 비즈니스 로직에 더 집중할 수 있게 데이터베이스 사용 기능을 클래스 레벨에서 추상화. 스프링 데이터에서 제공하는 인터페이스를 통해 스프링 데이터 사용 가능. 이 인터페이스에서는 CRUD를 포함한 여러 메서드 포함되어 있으며 알아서 쿼리를 만들어줌.
1. 스프링 데이터 JPA
: 스프링 데이터의 공통적인 기능에서 JPA의 유용한 기술이 추가된 기술
스프링 데이터의 인터페이스인 PagingAndSortingRepository를 상속받아 JpaRepository 인터페이스를 만들었으며, JPA를 더 편리하게 사용하는 메서드를 제공함.
// 메서드 호출로 엔티티의 상태를 변경하는 예시 → persist() 사용
@PersistenceContext
EntityManager em;
public void join() {
// 기존에 엔티티 상태를 바꾸는 방법 : 메소드 호출
Member member = new Member(1L, "홍길동");
em.persist(member);
}
// 기본 CRUD 메서드를 사용하기 위한 JpaRepository 상속 예시
public interface MemberRepository extends JpaRepository<Member, Long>{
}
- 스프링 데이터 JPA를 사용하면 리포지터리 역할을 하는 인터페이스를 만들어 데이터베이스의 테이블 조회, 수정, 생성, 삭제 같은 작업을 간단히 할 수 있음.
- JpaRepository 인터페이스를 우리가 만든 인터페이스(MemberRepository)에 상속받고 제네릭에는 관리할 <엔티티 이름, 엔티티 기본키의 타입>을 입력하면 기본 CRUD를 위해 만든 메서드를 사용할 수 있음
2. 스프링 데이터 JPA에서 제공하는 메서드 사용해보기
1. src/main/java/me.cool/springbootdeveloper/MemberService.java
@Service
public class MemberService {
@Autowired
MemberRepository memberRepository;
public void test() {
// 생성
memberRepository.save(new Member(1L, "A"));
// 조회
Optional<Member> member = memberRepository.findById(1L); // 단건 조회
List<Member> allMembers = memberRepository.findAll(); // 전체 조회
// 삭제
memberRepository.deleteById(1L);
}
}
- save() 메서드를 호출해 데이터 객체를 저장할 수 있음. 전달 인수로 엔티티 Member를 넘기면 반환값으로 저장한 엔티티를 반환받을 수 있음.
- findById() 메서드에 id를 지정해 엔티티를 하나 조회할 수 있음.
findAll() 메서드는 전체 엔티티를 조회함
- deleteById() 메서드에 id를 지정하면 엔티티를 삭제할 수 있음.
5.5 예제 코드 살펴보기
1. src/main/java/me.cool/springbootdeveloper/Member.java
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false)
private Long id;
@Column(name = "name", nullable = false)
private String name;
}
- @Entity 애너테이션
: Member 객체를 JPA가 관리하는 엔티티로 지정함. 즉 Member 클래스와 실제 데이터베이스의 테이블을 매핑시킴.
@Entity 속성 중에 name을 사용하면 name의 값을 가진 테이블 이름과 매핑되고, 테이블 이름을 지정하지 않으면 클래스 이름과 같은 이름의 테이블과 매핑됨.
여기서는 테이블 이름을 지정하지 않았으므로 클래스 이름과 같은 데이터베이스의 테이블인 member 테이블과 매핑됨.
ex) @Entity 애너테이션에서 테이블을 지정하고 싶은 경우 name 파라미터에 값을 지정
→ member_list 이라는 이름을 가진 테이블과 매핑
@Entity(name = "member_list")
public class Article {
// 생략
}
- protected 기본 생성자, 엔티티는 반드시 기본 생성자가 있어야 하고, 접근 제어자는 public 또는 protected여야 함. public보다는 protected가 더 안전하므로 접근 제어자가 protected인 기본 생성자를 생성함.
- @Id는 Long 타입의 id 필드를 테이블의 기본키로 지정함.
- @GeneratedValue는 기본키의 생성 방식을 결정함. 여기서는 자동으로 기본키가 증가하도록 지정.
** 자동키 생성 설정 방식 **
- AUTO : 선택한 데이터베이스 방언에 따라 방식을 자동으로 선택(기본값)
- IDENTITY : 기본 키 생성을 데이터베이스에 위임 (= AUTO_INCREMENT)
- SEQUENCE : 데이터베이스 시퀀스를 사용해서 기본 키를 할당하는 방법. 오라클에서 주로 사용
- TABLE : 키 생성 테이블 사용
- @Column 애너테이션은 데이터베이스의 컬럼과 필드를 매핑해줌.
** @Column 애너테이션의 속성 **
- name : 필드와 매핑할 컬럼 이름. 설정하지 않으면 필드 이름으로 지정해줌.
- nullable : 컬럼의 null 허용 여부. 설정하지 않으면 true(nullable)
- unique : 컬럼의 유일한 값(unique) 여부. 설정하지 않으면 false(non-unique)
- columnDefinition : 컬럼 정보 설정. default 값을 줄 수 있음.
2. src/main/java/me.cool/springbootdeveloper/MemberRepository.java
@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
}
- Repository는 엔티티에 있는 데이터들을 조회하거나 저장, 변경, 삭제를 할 때 사용하는 인터페이스
- 스프링 데이터 JPA에서 제공하는 인터페이스인 JpaRepository 클래스를 상속받아 간단하게 구현할 수 있음

** 핵심 요약 **
1. ORM은 객체와 데이터베이스를 연결하는 프로그래밍 기법이다.
2. JPA는 자바에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스이다.
- 엔티티는 영속성을 가진 객체를 의미한다.
- 엔티티 매니저는 엔티티를 관리하며 조회, 삭제, 수정, 생성하는 역할을 한다.
- 엔티티 매니저를 만드는 곳이 엔티티 매니저 팩토리이다.
- 엔티티 매니저는 엔티티를 영속성 컨텍스트에 저장한다는 특징이 있다.
- 영속성 컨텍스트는 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩의 특징을 가지고 있다.
- 엔티티의 상태는 분리, 관리, 비영속, 삭제 상태로 나뉜다.
3. 하이버네이트는 JPA의 구현체 중 대표적인 구현체로, 자바 언어를 위한 ORM 프레임워크이다.
4. 스프링 데이터 JPA는 JPA를 쓰기 편하게 만들어 놓은 모듈이다.
'Backend > <스프링 부트 3 백엔드 개발자 되기>' 카테고리의 다른 글
| 08장 스프링 시큐리티로 로그인/로그아웃, 회원 가입 구현하기 (0) | 2023.11.03 |
|---|---|
| 06장 블로그 기획하고 API 만들기 (0) | 2023.11.02 |
| 04장 스프링 부트 3와 테스트 (1) | 2023.10.31 |
| 03장 스프링 부트 3 구조 이해하기 (0) | 2023.10.29 |
| 02장 스프링 부트 3 시작하기 (0) | 2023.10.27 |