우선 설정할 것이 조금 있다.
build.gradle에서도 jpa 관련 의존성을 추가해야하며,
application.properties에서도 Hibernate도 설정해주어야한다.
또한, entity 부분도 JPA관련 설정들을 해주어야한다.
SpringBoot 환경에서는 EntityManagerFactory와 EntityManager를 자동으로 생성해준다.
위 application.properties에서 DB정보를 전달해주면 이를 토대로 EntityManagerFactory가 생성된다.
@PersistenceContext
EntityManager em;
@PersistenceContext 애너테이션을 사용하면 자동으로 생성된 EntityManager를 주입받아 사용할 수 있다.
Spring 프레임워크에서는 DB의 트랜잭션 개념을 애플리케이션에 적용할 수 있도록 트랜잭션 관리자를 제공한다.
@Transactional 애너테이션을 클래스나 메서드에 추가하면 쉽게 트랜잭션 개념을 적용할 수 있다.
JPA를 사용하여 DB에 데이터를 저장, 수정, 삭제하기 위해서는 트랜잭션 적용이 반드시 필요하다.
조회작업은 단순히 데이터를 읽는 용도이기 때문에 필수는 아니지만 필요한 경우가 있을 수 있다.
만약 조회 작업 기능에 트랜잭션이 필요하다면 readOnly = true 옵션을 설정하여 적용하는 것이 좋다.

스프링 컨테이너 환경속에서는 영속성 컨텍스트와 트랜잭션의 생명주기가 일치한다.
트랜잭션이 유지되는 동안은 영속성 컨텍스트도 계속 유지가 되기 때문에 영속성 컨텍스트의 기능을 사용할 수 있다.
그런데 어떻게 Service의 트랜잭션이 적용된 메서드에서 Repository의 메서드를 호출하는 데까지 Transaction을 유지할 수 있는 것일까?
Spring은 이러한 상황에서 트랜잭션을 제어할 수 있도록 트랜잭션 전파 기능을 제공하고 있다.
@Transactional의 옵션중 propagation옵션을 통해 지정할 수 있다.
기본은 REQUIRED이며 이는 부모 메서드에 트랜잭션이 존재하면 자식메서드의 트랜잭션은 부모의 트랜잭션에 합류할수 있는 것이다.


Spring Data JPA에서는 JpaRepository 인터페이스를 구현하는 클래스를 자동으로 생성해준다.
따라서 인터페이스의 구현 클래스를 직접 작성하지 않아도 JpaRepository 인터페이스를 통해 JPA의 기능을 사용할 수 있다.
JpaRepository<"@Entity 클래스", "@Id 의 데이터 타입">를 상속받는 interface 로 선언한다.
Spring Data JPA에서는 시간에 대해서 자동으로 값을 넣어주는 기능인 JPA Auditing을 제공한다.
@Getter
@MappedSuperclass
// JPA Entity 클래스들이 해당 추상 클래스를 상속할 경우
//createdAt, modifiedAt 처럼 이 클래스에 선언한 멤버변수를 컬럼으로 인식할 수 있다.
@EntityListeners(AuditingEntityListener.class)
//해당 클래스에 Auditing 기능을 포함시켜준다.
public abstract class Timestamped {
@CreatedDate
//Entity 객체가 생성되어 저장될 때 시간이 자동으로 저장된다.
@Column(updatable = false)
//최초 생성 시간이 저장되고 그 후에는 수정되면 안되기 때문에 false 옵션 추가
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createdAt;
@LastModifiedDate
//조회한 Entity 객체의 값을 변경할 때 변경된 시간이 자동으로 저장된다.
//처음 생성 시간이 저장된 이후 변경이 일어날 때마다 해당 변경시간으로 업데이트된다.
@Column
@Temporal(TemporalType.TIMESTAMP)
//날짜 타입을 매핑할 때 사용
private LocalDateTime modifiedAt;
}
Spring Data JPA에서는 메서드 이름으로 SQL을 생성할 수 있는 Query Methods 기능을 제공한다.
JpaRepository 인터페이스에서 해당 인터페이스와 매핑되어있는 테이블에 요청하고자하는 SQL을 메서드 이름을 사용하여 선언할 수 있다.
SimpleJpaRepository 클래스가 생성될 때 JpaRepository 인터페이스의 모든 메서드를 자동으로 구현해준다.
따라서 SQL을 직접 짜는 것이 아니라 해당 패턴을 사용한 메서드를 선언하기만 하면 사용할 수 있는 것이다.
예를 들어, findAllByOrderByModifiedAtDesc 해당 메서드 이름을 보면 modifiedat이라는 수정시간을 기준으로 전체 데이터를 내림차순으로 가져오는 SQL을 만든것이라고 보면된다.
또다른 예로 List<Memo> findAllByUsername(String username);
위와 같이 선언했을 경우 ByUserName에 값을 전달해주어야하기 때문에 파라미터에 해당 값의 타입과 변수명을 선언해준다.
즉, Query Methods는 메서드의 파라미터를 통해 SQL에 필요한 값을 동적으로 받아 처리할 수 있다.