✅ DB H2
- 내장형 H2 데이터베이스
H2는 Server Mode, In-memory Mode, Embeded Mode라는 세가지 방식으로 사용할 수 있다.
1. Server Mode
- 서버 모드는 현업에서 사용하는 모드로 컴퓨터에 DB 엔진을 설치하고 엔진을 구동하여 사용하는 방식입니다.
- 애플리케이션과 DB가 분리되어 있기 때문에 여러 애플리케이션에서 동일한 DB를 사용하기에 적합합니다.
- 직접 엔진을 설치하여 사용하는 방식.
- 애플리케이션과 상관 없는 외부에서 DB 엔진이 구동된다.
- 데이터가 애플리케이션 외부에 저장되므로 애플리케이션을 종료해도 데이터가 사라지지 않는다.
2. In-memory Mode
- 인메모리 모드는 애플리케이션에 DB 엔진이 내장되어 애플리케이션과 함께 실행되고 종료되는 방식입니다.
- 데이터가 애플리케이션의 메모리에 저장되기 때문에 애플리케이션이 종료되면 모든 데이터가 사라지는 휘발성의 특징을 갖고 있습니다.
- 이러한 특징으로 인해 단위 테스트 등에서 많이 사용됩니다.
- 스프링부트 프로젝트에서 H2를 인메모리 모드로 사용하려면 application.yml 또는 application.properties에서 아래와 같이 설정하면 됩니다.
- 엔진을 설치하지 않고 애플리케이션 내부의 엔진을 사용하는 방식.
- `build.gradle` 및 `application.properties` 설정을 통해 실행 가능하다.
- 애플리케이션을 실행하면 DB 엔진이 함께 실행되고 애플리케이션을 종료하면 DB 엔진이 함께 종료된다.
- 데이터가 애플리케이션의 **메모리**에 저장되기 때문에 애플리케이션을 종료하면 데이터가 사라진다.
# application.yml
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:{DB 이름}
username: sa
password:
# application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:{DB 이름}
spring.datasource.username=sa
spring.datasource.password=
3. Embedded Mode
- 임베디드(내장) 모드는 인메모리 모드와 동일하게 애플리케이션에 DB 엔진이 내장되어 애플리케이션과 함께 실행되고 종료되는 방식입니다.
- 인메모리 모드와 다른 점은 데이터를 로컬에 저장하기 때문에 데이터 휘발에서 자유롭다는 점입니다. 이로 인해 간단한 애플리케이션에서 사용하기 좋습니다.
- 스프링부트 프로젝트에서 H2를 임베디드 모드로 사용하는 방법은 url을 제외하고 동일하게 설정해주면 됩니다.
- 엔진을 설치하지 않고 애플리케이션 내부의 엔진을 사용하는 방식.
- `build.gradle` 및 `application.properties` 설정을 통해 실행 가능하다.
- 애플리케이션을 실행하면 DB 엔진이 함께 실행되고 애플리케이션을 종료하면 DB 엔진이 함께 종료된다.
- 데이터가 애플리케이션 **외부**에 저장되므로 애플리케이션을 종료해도 데이터가 사라지지 않는다.
# application.yml
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:{DB가 저장될 경로}
username: sa
password:
# application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:{DB가 저장될 경로}
spring.datasource.username=sa
spring.datasource.password=
✅ DB 드라이버
- 드라이버의 역할: 데이터베이스 드라이버는 애플리케이션과 데이터베이스 간의 통신을 중개하는 역할을 합니다. 마치 우체부가 편지를 전달하는 것처럼, 드라이버는 애플리케이션의 요청을 데이터베이스가 이해할 수 있는 언어로 변환합니다.
- 드라이버의 종류: 다양한 데이터베이스 시스템마다 호환되는 드라이버가 있습니다. 예를 들어, Oracle, MySQL, PostgreSQL 등 각 데이터베이스 제품에 맞는 특정 드라이버가 필요합니다.
✅ My Batis
- MyBatis 는 RowMapper 가 가지고있는 단점인 “반복되는 코드”를 줄이고 “함께있는 프로그램 코드와 쿼리 코드를 분리하여 관리”하고 싶은 니즈를 반영하여 탄생하였습니다.
- SQL Mapper 두번째 주자로 MyBatis 탄생
- 반복적인 JDBC 프로그래밍을 단순화 하고싶다.
- SQL 쿼리들을 XML 파일에 작성하여 코드와 SQL 을 분리 하고싶다.
- MyBatis 특징
- jdbc로 처리하는 코드의 설정(Connection) 부분을 줄이고 실제 sql문에 연결함으로서 빠른 개발이 가능하게 한다. (SQL Mapper 특징)
- MyBatis 코드는 map 인터페이스(또는 클래스)와 SQL 쿼리와 ResultSet 매핑을 위한 xml 및annotation을 사용한다.
- 다른 방식에 비해 객체자체보다 쿼리에 집중할 수 있다.\
- MyBatis 한계점
- 결국 SQL을 직접 작성하는것은 피곤하다…(DB 기능에 종속적)
- 테이블마다 비슷한 CRUD 반복, DB타입 및 테이블에 종속적이다.
✅ RDB 와 ORM
- 우리가 JAVA 를 사용하는 거면, 중요하게 짚고 넘어가야하는 것이 있다.
1. RDB와 Java의 패러다임 차이
RDB (관계형 데이터베이스)
- 데이터 중심: 데이터는 테이블(행과 열)로 구성됨.
- 정규화: 중복을 최소화하고 참조를 통해 관계를 표현 (예: user_id를 다른 테이블에서 참조).
- 관계(Relation): 외래 키를 통해 여러 테이블을 조합해서 하나의 결과를 만들도록 설계.
Java (또는 대부분의 객체지향 언어)
- 객체 중심: 현실 세계의 개념을 클래스와 객체로 표현.
- 포함(Composition) 중심 설계: 다른 객체를 포함시켜 관계를 표현함.
- 행위(Behavior)와 상태(State)를 함께 다룸.
2. 패러다임 충돌
측면 | RDB | JAVA |
데이터 표현 | 테이블(정규화된 구조) | 객체(캡슐화, 포함 관계) |
관계 표현 | 외래 키, JOIN | 객체 간 참조 (has-a 관계) |
데이터 접근 | SQL로 질의 (절차적 접근) | 메서드 호출로 객체 조작 |
상태 관리 | 정적 데이터 중심 | 동적 객체 상태, 생명 주기 관리 |
- 테이블과 객체의 구조가 일대일로 매칭되지 않음.
- 객체의 계층적 구조를 테이블로 표현하기 어려움.
- SQL을 직접 작성하고, 결과를 객체로 수동 변환해야 함 (반복 코드 증가).
3. 그래서 등장한 ORM
- ORM(Object-Relational Mapping)은 이 둘을 연결해주는 "자동 매핑 도구"입니다.
4. ORM의 핵심 역할:
- 자바 클래스 ↔ 데이터베이스 테이블 자동 매핑
- 객체의 속성 ↔ 테이블의 컬럼 자동 매핑
- 객체 관계 ↔ 외래 키 관계 매핑
- SQL을 직접 작성하지 않고도 CRUD 수행 가능
> 대표 ORM 프레임워크:
- Java에서는 Hibernate, JPA(Java Persistence API) 가 대표적.
5. ORM 도입의 장점
- 생산성 향상: SQL 작성이 줄고, 반복 코드 감소.
- 유지보수 용이: 테이블 구조 변경 시 Java 코드만 수정하면 됨.
- 객체 지향적으로 코드 구성 가능: OOP의 장점을 살릴 수 있음.
- 트랜잭션, 캐싱 등 부가 기능 제공: 성능과 안정성 향상.
6. ORM이 필요한 이유 요약
- 관계형 DB는 테이블 중심이고, Java는 객체 중심이기 때문
- 구조가 다르므로 매핑을 자동화하는 기술이 필요함
- 객체와 관계형 테이블 간의 불일치를 해소하기 위해 ORM 도입
✅ 쓰기지연
1. 쓰기 지연이 발생하는 시점
- flush() 동작이 발생하기 전까지 최적화한다.
- flush() 동작으로 전송된 쿼리는 더이상 쿼리 최적화는 되지 않고, 이후 commit()으로 반영만 가능하다.
2. 쓰기 지연 효과
- 여러개의 객체를 생성할 경우 모아서 한번에 쿼리를 전송한다.
- 영속성 상태의 객체가 생성 및 수정이 여러번 일어나더라도 해당 트랜잭션 종료시 쿼리는 1번만 전송될 수 있다.
- 영속성 상태에서 객체가 생성되었다 삭제되었다면 실제 DB에는 아무 동작이 전송되지 않을 수 있다.
- 즉, 여러가지 동작이 많이 발생하더라도 쿼리는 트랜잭션당 최적화 되어 최소쿼리만 날라가게된다.
- 하지만, Indentity 같은 경우에는 쓰기지연 적용이 안된다.
✅ 객체끼리의 관계
@OneToOne
- 일대일 관계를 나타내는 매핑 정보
- 1:1 관계를 지정하기에 앞서 이것이 꼭 물리적으로 테이블이 분리되어야 하는지에 대해 생각해 봐야 합니다.
- 1:1 관계로 구성 한다는 것은 결국 하나의 목적에 부합되는 공통된 데이타를 관리한다고 볼 수 있으며 이것은 하나의 테이블에서 관리 할 수 있는 데이타일 가능성이 높다는 의미입니다.
- 즉, 의도적 중복이 아니라면 사용할일이 없다는 말
- 의도적 중복 예시) 버블 구독상품을 사서 채팅방이 생길경우. 구독상품과 채팅방은 1:1 관계
@OneToMany
- 일대다 관계를 나타내는 매핑 정보
- @OneToMany가 단방향으로 쓰이면 문제가 발생할 수 있다.
- 속도를 위해 기본적으로 FetchType 설정이 LAZY 로 설정되어 있습니다.
- 속성
- mappedBy : 연관관계의 주인 필드를 선택한다.
- fetch : 글로벌 페치 전략 설정
- cascade : 영속성 전이 기능을 사용한다.
- targetEntity : 연관된 엔티티의 타입 정보를 설정한다.
@ManyToOne
- 다대일 관계를 나타내는 매핑 정보
- 속성
- optional (default true) : false로 설정하면 연관된 엔티티가 반드시 있어야 함.
- fetch : 글로벌 패치 전략 설정
- ✋ 기본이 EGEAR 로 설정되어있으나 실무에서는 기본 LAZY로 설정하는것 추천!
- cascade : 영속성 전이 기능 사용
- targetEntity : 연관된 엔티티의 타입 정보 설정 (targetEntity = Member.class 식으로 사용)
@JoinColumn
- 외래 키 매핑 시 사용 (Join 을 요청하기 위한 매핑정보로 쓰인다.)
- @ManyToOne 어노테이션과 주로 함께 쓰인다. (조인대상 컬럼 지정기능을 안쓸거면 생략해도 됨)
- name 속성은 매핑할 외래키의 이름
- 어노테이션을 생략해도 외래 키가 생성됨.
- 생략 시 외래키의 이름이 기본 전략을 활용하여 생성된다.
- 속성
- name : 매핑할 외래 키의 이름
- referencedColumnName : 외래 키가 참조하는 대상 테이블의 컬럼명
- foreignKey : 외래 키 제약조건 지정 (테이블 생성 시에만 적용됨)
- unique/nullable/insertable/updateable/columnDefinition/table : @Column의 속성과 같음
'백엔드 부트캠프 > TIL' 카테고리의 다른 글
[내일배움캠프Spring-56일차] 주특기 플러스 과제 SpringSecurity 로 전환하기 ! (0) | 2025.05.07 |
---|---|
[내일배움캠프Spring-55일차] Qeury Dsl 설정하기 (0) | 2025.05.07 |
[내일배움캠프Spring-53일차] Spring Security에서 세션 기반 인증 vs JWT 기반 인증 (0) | 2025.05.01 |
[내일배움캠프Spring-52일차] 트랜잭션 복습 (0) | 2025.04.30 |
[내일배움캠프Spring-51일차] AOP 로깅 처리 를 구현하자 ! (0) | 2025.04.29 |