Before Starts :
데이터 저장 -> 영속성이라고 함
그와 관련된 프레임 워크 : 영속성 프레임 워크 (DB, File, 외부저장소(Network사용))
R-DB : 관계형 데이터베이스 모델을 자주 사용한다.
1) Spring - data - JPA
2) Spring - Jdbc
3) MyBatis
등 다양하게 존재한다.
DB 정의
관계형 모델
Column : 데이터의 속성
Row : 컬럼들의 집합
key, primary key, foreign key
Relationship : 테이블 사이의 관계
transaction : data의 일관성을 유지하기 위해 R-DB가 제공하는 기능
SQL : DB를 사용하기 위해 쓰는 query language(DDL, DML, DCL)
H2 Database
JDBC : R-DB에 저장된 데이터를 접근 및 조작할 수 있게 해주는 자바 API
개발자는 DB종류에 상관 없이 JDBC api만을 이용하면 된다
JDBC 구조
JDBC API
DataSource : Connection 객체를 사용해서 App과 DB 사이의 연결을 해줘, Sequel을 실행할 수 있게 해준다. 하지만 아무나 DB에 접근해서는 안되기 때문에 상세한 정보(host, port, id, pw)를 제공해야 connection을 받아 올 수 있다. Connection Pooling을 일반적으로 제공을 해준다. 따라서 성능에 대한 확장성이 좋다.
Connection Pool
-> 시스템 자원 요구 하는데 필요한 시간을 runtime에 요구하지 않게 됨
Thread-Safe : 멀티쓰레드 환경에서 하나의 공유 자원을 여러 쓰레드가 접근시(running) 문제가 생길 수 있는 상황을 문제가 생기지 않게 처리한것.
즉, Spring MVC Connection pool은 Thread-safe하다. 왜냐? Connection pool의 갯수보다 많은 thread 요청은 wait() 상태로 변해있기 때문이다.
장점 :
구현체 종류
Java에서 data access 기술
Spring Framework JdbcTemplate
DBCP를 사용할 때, 기본 설정(initial size, max total, min total, max Idle)은 통일시키는게 일반적으로 좋다. runtime에 connection의 숫자가 바뀌는것은 좋지 않기 때문
해당 과정으로 잘 연결이 되었는지 확인할 수 있다.
ORM : (Object-Relational Mapping)
JPA : (Java Persistence API -> Jakarta Persistence API)
구현 : Hibernate, EclipseLink, DataNucleus
JPA를 써야 하는 이유?
SQL 중심적인 개발에서 객체 중심(자바) 으로 개발하기 위해서
패러다임 불일치 해결 : JPA는 객체와 관계형 데이터베이스 사이의 패러다임의 불일치로 인해 발생하는 문제 (상속, 연관관계, 객체 그래프 탐색 등)를 해결
생산성
데이터 접근 추상화와 벤더 독립성
Spring Framework와 JPA
Spring Data
Spring Data JPA
Transaction : 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산(query)들을 의미
Transaction 예시) [송금예제] a->b 만원 송금
Transaction 속성) ACID - Atomicity, Consistency, Isolation, Durability
Atomicity : 트랜잭션의 수행결과는 데이터베이스에 전부 반영되거나, 전부 반영되지 않아야 한다
- commit, rollback
Consistency : 트랜잭션 수행 후 데이터 모델의 모든 제약조건을 만족해야 한다
- Data save시 bigint가 저장되어야 하는데, str이 저장되면 안됨
- PK, FK, Unique등...
Isolation : 트랜잭션 수행 시 다른 트랜잭션이 영향을 미치지 않아야 한다
- MultiThread 상황에서 각각의 트랜잭션이 다른 트랜잭션에 영향X
- read uncommited (dirty read)
- read committed
- repeatable read (phantom read)
- serializable
Durability : 트랜잭션의 성공결과는 장애 발생 후에도 변함없이 보관되어야 한다
- 앞서 설명한 영속성) 정상 저장된 데이터는 DBMS가 책임지고 DB에 기록하는 성질
Spring Framework의 트랜잭션 추상화 : PlatformTransactionManager
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) /*..*/;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
해당 인터페이스가 있어야 메소드에 @Transactional(AOP)을 달 수 있음
선언적 트랜잭션
@Transactional
*AOP가 정상적으로 동작하기 위해서 어떤 조건 필요?
1) 대상 객체가 Spring Bean(@Service, @Component, @Repository, ...)
- 일반적으로 Service에 usecase를 담기 때문에 주로 Service에 AOP 적용
2) 해당 Method가 Public
*Datasource에 PlatformTransactionManager를 Bean으로 만들고 트랜잭션을 달아줘야함 -> JPAConfig로 변경
JPA를 쓰기 위해....
1) @EnableJpaRepositories(basePackageClasses = RepositoryBase.class) 선언
2) @Configuration 선언
3) LocalContainerEntityManagerFactoryBean 만들기
- LocalContainerEntity 만드는 Bean임
- JPA에서 entity를 관리하고, life cycle 관리 : Entity Manager
- EntityManager에서 지원하는 persist, merge, find, remove 등의 함수 지원
- Entity : Table
4) JPA Vendor 선언 (JpaVendorAdapter)
5) Properties 선언
6) PlatformTransactionManager 선언
EntityManager : 엔터티의 저장, 수정, 삭제, 조회 등 엔터티와 관련된 모든 일을 처리하는 관리자
public interface EntityManager {
public <T> T find(Class<T> entityClass, Object primaryKey);
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties);
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode);
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties);
public void persist(Object entity);
public <T> T merge(T entity);
public void remove(Object entity);
// ...
}
EntityManagerFactory : EntityManager를 생성하는 팩토리
public interface EntityManagerFactory {
public EntityManager createEntityManager();
public EntityManager createEntityManager(Map map);
public EntityManager createEntityManager(SynchronizationType synchronizationType);
public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map);
// ...
}
JPA/Hibernate Logging
SQL
<logger name="org.hibernate.SQL" level="debug" additivity="false">
<appender-ref ref="console" />
</logger>
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="trace" additivity="false">
<appender-ref ref="console" />
</logger>
Entity 맵핑
Entity // Entity Mapping
Entity? JPA를 이용하여 DB Table과 Mapping 할 Class
Entity Mapping? Entity Class에 DB Table과 column, pk, fk 등을 설정하는 것
어노테이션
Entity를 생성시 약속 : NoArgsConstructor, Class 일것(interface, enum 안됨), final을 못씀, @id는 구분자(pk)가 필요함
*final 변수 : 값 변경 불가, final method : 오버라이딩 불가능, final class : 상속 불가능
예제)
@Entity
@Table(name = "Members")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Column(name = "created_dt")
private LocalDateTime createdDate;
}
필드와 컬럼 맵핑
@Column
@Temporal
*TestCase 작성시 클래스 상단에 @Transactional을 달면 모든 TestCase가 rollback이 된다
기본키 (PK) Mapping 전략
자동생성
직접할당
예제)
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "item_id")
private Long itemId;
// ...
}
public @interface GeneratedValue {
GenerationType strategy() default AUTO;
String generator() default "";
}
public enum GenerationType {
TABLE,
SEQUENCE,
IDENTITY,
AUTO
}
복합키 (Composite key)
IdClass : 직접 Get메소드 가능
EmbeddedId : 조금 추상화된 방식으로 PK가 디자인 된 방식을 사용
두 방식 모두 외부에서 참조할 수 있게 Static으로 구성해야 함 또한 Implements Seralizable 해야함
복합키 클래스 제약조건:
EntityManager랑 EntityManagerFactory는 1:1 매핑이 되어서 DB를 두개쓰면 Manager도 2개, Factory도 2개다
EntityManagerFactory : EntityManager를 생성하는 팩토리
데이터베이스를 하나만 사용하는 Application은 일반적으로 팩토리를 하나만 쓴다(비용 매우 큼(cpu,memory))
- thread safe
EntityManager : Entity의 저장, 수정, 삭제, 조회 등 Entity와 관련된 모든 일을 처리하는 관리자
- Factory가 생성함 : 생성비용이 낮음
- Thread Safe하지 않다!
- 절대 여러 thread간에 공유하면 안됨
- Transaction의 life-cycle과 정확히 일치함
- 각각의 요청마다 별도의 Manager를 생성해야 함
영속성 컨텍스트(Durability Context) : Entity를 영구저장하는 환경
@PersistenceContext
Entity의 생명주기
비영속, 영속, 준영속, 삭제
비영속(new/transient) : 영속성 컨텍스트와 전혀 관계 없는 상태
- new Foo() << 상태임(persist()) 해야 Manager가 manage 할 수 있게됨
영속(managed) : 영속성 컨텍스트에 저장된 상태
- EntityMageger.persist(new Foo)
- persist, find, merge
준영속(detached) :영속성 컨텍스트에 저장되었다가 분리된 상태
- DB의 상태와 Application의 상태가 다를 때(update ~~ set ~~ 하면 상태가 달라짐)
- detach, clear, close
삭제(removed) : 삭제된 상태
- remove
DB에 데이터 반영 : flush() - transactionManager가 트랜잭션이 끝나면 flush() 해줌
영속성 컨텍스트가 Entity를 관리하면 얻을 수 있는 이점