
: Spring 기반의 애플리케이션을 개발하기 쉽도록 많은 부분을 자동화하여, 사용자가 편하게 Spring을 활용할 수 있도록 돕는 프레임워크
: 여러 기술과 라이브러리에 대한 종속성들을 수동으로 추가하지 않아도 되며, 간편하게 필수 의존성을 관리할 수 있게 해주는 도구이다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

: Maven, Gradle 모두 Java 기반 프로젝트를 관리하고 빌드하는 데 사용되는 도구


: 과거 소프트웨어 개발 과정에서 발견된 설계 노하우를 추척해, 방법으로 만들어 규약으로 정리한 것으로,
특정 문맥에서 공통적으로 발생할 수 있는 문제에 대해 재사용 가능한 해결책이 된다.

: Spring에서 제공하는 웹 모듈로, 사용자의 HTTP 요청을 처리하여 다양한 응답(단순 Text, REST 형식, html 등)을 지원하는 프레임워크이다.

클라이언트 요청을 Dispatcher Servlet이 받는다.
요청 정보를 기반으로, 이 요청을 처리할 컨트롤러를 Handler Mapping으로 검색한다.
검색된 컨트롤러 정보를 Dispatcher Servlet에 리턴한다.
Handler Adapter에게 컨트롤러에 있는 Handler Method를 호출하도록 위임한다.
해당 컨트롤러의 Handler Method를 호출한다.
Model 데이터(응답)를 Handler Adapter에게 전달한다.
전달 받은 Model 데이터와 View 정보를 Dispatcher Servlet에게 전달한다.
전달 받은 View 정보를 View Resolver에게 전달해, 알맞은 View 검색을 요청한다.
검색한 View를 Dispatcher Servlet에 리턴한다.
전달받은 View 객체를 통해 Model 데이터를 넘기면서, 클라이언트에 전달할 응답 데이터 생성을 요청한다.
응답 데이터를 Dispatcher Servlet에게 전달한다.
전달 받은 응답 데이터를 최종 클라이언트에게 전달한다.
정리하면,
Dispatcher Servlet은 애플리케이션 가장 앞에 배치되어,
다른 구성요소와 상호작용하며 클라이언트 요청을 처리한다.
: 데이터를 영구적으로 저장 및 관리하는 부분
데이터베이스 관리 시스템 (DBMS)을 사용해 구현된다.
: 데이터를 생성한 프로그램의 실행이 종료되더라도 사라지지 않는 특성
: Java에서 데이터베이스에 접근할 수 있도록 하는 기본 DB 프로그래밍 방법이다.
규격에 따라 정의된 인터페이스들을 구현한 Driver 클래스를 사용해, 서로 다른 DB를 동일한 방법으로 사용가능하다.
SQL 중심 기술
<select id="findNews" resultType="News"> SELECT * FROM NEWS WHERE news_id = #{newsId} </select>객체 중심 기술
데이터를 객체 관점으로 바라보는 기술
SQL 쿼리문을 직접 작성하기 보다는 Java 객체를 이용해 애플리케이션 내부에서 객체를 SQL 쿼리문으로 자동 변환 후 DB 테이블에 접근한다.
JPA
: 객체지향 프로그래밍은 클래스를 사용, RDB는 테이블을 사용한다. 객체 모델과 관계형 모델 간에는 패러다임의 불일치가 존재한다.
그럼에도 ORM은 OOP와 RDB를 연결할 계층의 역할로 제시된 패러다임으로, 객체 간 관계를 바탕으로 SQL을 자동 생성하여, 불일치를 해결해준다.
[출처] https://gmlwjd9405.github.io/2019/08/04/what-is-jpa.html#google_vignette
: Java 애플리케이션에서 관계형 데이터베이스를 객체-관계 방식으로 사용할 수 있도록 만든 인터페이스

: 엔티티를 영구 저장하는 환경. 애플리케이션과 DB 사이에서 객체를 보관하는 가상의 DB 역할을 한다.
엔티티 매니저 (EntityManager)를 통해 엔티티를 저장하거나 조회하면,
영속성 컨텍스트에 엔티티를 보관하고 관리한다.
1차 캐시
: 영속성 컨텍스트 내부에 갖는 캐시
ID, 엔티티를 키, 값으로 하는 Map 형식으로 이루어져 있다.
데이터 조회 시 1차 캐시에 존재하면 DB에 접근하지 않아도 된다.
쓰기 지연 SQL 저장소
: 단일 트랜잭션(Transaction)에서 이루어지는 쿼리를 쌓아놓는 공간
트랜잭션이 커밋되는 순간 한 번에 DB로 쿼리를 날린다.
DB 연결 시간을 줄이고, 한 트랜잭션이 테이블에 접근하는 시간을 줄일 수 있다.
변경 감지
: 영속성 컨텍스트 1차 캐시에는 "스냅샷 컬럼"이 존재한다.
1차 캐시 저장 순간의 데이터를 스냅샷에 기록하고,
flush() 시점에 변경된 부분이 있으면 자동으로 UPDATE 쿼리를 보낸다.
지연 로딩(Lazy Loading)
: 연관관계 매핑되어 있는 엔티티 조회 시, 우선 프록시 객체를 반환하고
실제로 필요할 때 쿼리를 날려 데이터를 가져오게 한다.

: Spring 프레임워크에서 제공하는 모듈 중 하나. 개발자가 더 쉽고 편하게 JPA를 사용할 수 있도록 해준다.
: 기본 DB에 대한 특정은 유지하면서, 데이터 액세스 방법에 대해 익숙한 접근 방법을 제시하는 목적을 가진 Spring 기반 프로그래밍 모델
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:~/{스키마 이름}
username: {사용자 이름}
password: {사용자 암호}
jpa:
hibernate:
ddl-auto: update
show-sql: true
: JPA를 이용해 DB 테이블과 상호작용하기 위해 DB Table ←→ Entity Class 간 매핑 작업이 필요하다.
엔티티 클래스를 생성하면 DB 테이블 구조가 자동으로 만들어진다.
(application.yml의 ddl-auto 설정에 따라 테이블 생성 결정)
@Entity
@Getter @Setter
@NoArgsConstructor @AllArgsConstructor
public class News {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long newsId;
@Column(name = "news_title", nullable false, length = 255)
private String title;
@Column(nullable = false)
private String content;
}
@NoArgsConstructor
: 매개변수가 없는 기본 생성자 생성
Reflection을 위해 필수적이다.
@AllArgsConstructor
: 모든 필드 값을 매개변수로 받는 생성자 생성
@Getter / @Setter
: getter / setter 메서드를 자동 생성한다.
필드에 사용하면 해당 필드에 대해서만, 클래스에 사용하면 모든 필드에 대해서 메서드를 만든다.
@Entity
: 영속성 컨텍스트가 엔티티로 인식하고, JPA가 테이블과 매핑하게끔 알려준다.
@Table
: 엔티티 클래스를 DB의 특정 테이블로 매핑할 때 사용
테이블 이름, 카탈로그, 스키마, 유니크 ㅔㅈ약조건 등 명시적으로 정의 가능하다.
@Id
: PK 설정을 위한 식별자 필드.
엔티티의 필드를 테이블의 ID 기본 키 컬럼에 매핑한다. @GeneratedValue와 함께 사용
@GeneratedValue
: PK 생성 전략을 지정한다.
strategy 속성(IDENTITY, SEQUENCE, TABLE, AUTO 등)으로 지정 (직접 할당, 자동 생성 등)
@Enumerated
: Java의 enum 타입을 매핑할 때 사용한다.
EnumType.ORDINAL(인덱스를 DB값으로 저장) / EnumType.STRING(이름을 DB값으로 저장)
그 외의 Annotations
| Annotation | Description |
|---|---|
| @Temporal | 날짜 타입 (Date/Calender) 매핑 |
| @CreationTimestamp | 엔티티가 DB에 저장될 때의 시간을 자동 기록 |
| @UpdateTimestamp | 엔티티가 생성 or 업데이트될 때 시간을 자동 기록 |
| @Transient | 특정 필드를 DB에 매핑하지 않음 |
| @Lob | DB의 BLOB, CLOB 타입 매핑 (DB에서 큰 데이터 저장에 사용하는 유형) |
: 엔티티 클래스 간 관계를 만들어주는 것.
객체는 참조를 사용해 관계를 맺고, 테이블은 외래키를 사용해서 관계를 맺는다.
class Student {
private Department department;
...
}
class Department {
private List<Student> students;
...
}
: 'EntityA'가 'EntityB'를 참조하고 있지만,
'EntityB'는 'EntityA'를 참조할 수 없다.
@Entity
public class EntityA {
@ManyToOne
private EntityB entityB;
...
}
@Entity
public class EntityB {
...
}
: 두 엔티티 간 서로 참조 가능한 관계
양쪽에서 서로 참조해야 하거나, 접근이 필요한 경우 사용한다.
양방향 연관관계 매핑을 위해서는 "연관관계의 주인"을 정해야 한다.
public class News {
...
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
public class User {
...
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<News> news;
}
양방향 매핑 시에는 무한 루프에 빠지지 않게 조심해야 한다.
(toString(), equals(), hashCode() 메서드 사용 시 특히 주의)
public class News {
...
@ManyToOne
@JoinColumn(name = "user_id")
@JsonBackReference
private User user;
}
public class User {
...
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
@JsonManagedReference
private List<News> news;
}
// 주 테이블 (사람)
@Entity
public class Member {
@Id @GeneratedValue(strategy = GeneratedType.IDENTITY)
private Long memberId;
@Column
private String name;
}
// 대상 테이블 (사물함)
@Entity
public class Locker {
@Id @GeneratedValue(strategy = GeneratedType.IDENTITY)
private Long lockerId;
@Column
private String name;
@OneToOne
@JoinColumn(name = "member_id")
private Member member;
}
// 주 테이블 (사람)
@Entity
public class Member {
@Id @GeneratedValue(strategy = GeneratedType.IDENTITY)
private Long id;
@OneToOne(mappedBy = "member")
private Address Address;
}
// 대상 테이블 (주소)
@Entity
public class Locker {
@Id @GeneratedValue(strategy = GeneratedType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "member_id")
private Member member;
}
@Entity
public class Member {
@Id @GeneratedValue(strategt = GeneratedType.IDENTITY)
private Long memberId;
@Column
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
@Entity
public class Team {
@Id @GeneratedValue(strategt = GeneratedType.IDENTITY)
private Long teamId;
@Column
private String name;
}
@Entity
public class Member {
@Id @GeneratedValue(strategt = GeneratedType.IDENTITY)
private Long memberId;
@Column
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
}
@Entity
public class Team {
@Id @GeneratedValue(strategt = GeneratedType.IDENTITY)
private Long teamId;
@Column
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
}