JPA 사용이유
관계형데이터베이스 -> 데이터를 어떻게 저장할지 초점을 맞춤
객체지향 프로그래밍 -> 메세지 기반 기능과 속성을 한곳에다 관리하는 기술
둘은 시작점부터 틀림 그래서 패러다임 불일치 발생...
그러면? 개발방향은 데이터베이스 모델링에만 집중하는 현상 발생. (ex:mybatis)
그래서 JPA는 중간에서 패러다임을 일치시켜주기 위한 기술
개발자는 객체지향 프로그래밍을하고 SQL 종속적인 개발을 하지않아도됨.
Spring Data JPA
구현체 교체의 용이성 / 저장소 교체의 용이성
실무에서 쓰려면 객체지향프로그램과 관계형데이터 베이스 둘다 이해해야됨 ( 어려움)
사용하려면 디펜던시에 추가해주면됨 . (* h2 메모리상 디비툴)
package com.bookStudy.boo.springboot.domain.posts;
import com.bookStudy.boo.springboot.domain.BaseTimeEntity;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter
@NoArgsConstructor //기본 생성자 자동추가 . public Posts(){}
@Entity // 테이블과 링크될 클래스
public class Posts extends BaseTimeEntity {
@Id //PK 필드
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto_increment
private Long id;
@Column(length = 500, nullable = false) //굳이 선언하지않더라도 모두 칼럼이된다 나머지 필드는. 사용할경우 옵션을 주기위해
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
//실제 DB 테이블과 매칭될 클래스이며 보통 Entity 라고도 한다. JPA 사용시 데이터 작업할경우 실제쿼리보다 이 클래스 수정 통해작업?
// 해당 클래스의 빌더 패턴 클래스 생성? 생성자 상단에 선언시 생성자에 포함된 필드만 빌더에 포함
@Builder
public Posts(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
public void update(String title, String content) {
this.title = title;
this.content = content;
}
}
테이블과 직접 링크되는 클래스다. 기본키 설정 및 빌더 클래스(생성자랑 비슷한듯하다)만들어 생성시 컬럼명을 명확히 알수있음
setter 메서드가 없는대신 추가로 클래스내에 퍼블릭 메소드를 만들어 메세지를 보내 상태값을 변경하면 된다.
package com.bookStudy.boo.springboot.domain.posts;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface PostsRepository extends JpaRepository<Posts, Long> {
@Query("SELECT p FROM Posts p ORDER BY p.id DESC")
List<Posts> findAllDesc();
}
레파지토리 클래스이다 엔티티,키 타입을 입력하면 된다.
자동적으로 기본 CRUD 클래스가 생성되는 데 코드상에는 안나와있다
따로 쿼리를 만들고싶으면 @Query 해서 붙여주면 될듯.
package com.bookStudy.boo.springboot.domain.posts;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.time.LocalDateTime;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest // H2 자동으로 실행해준당
public class PostsRepositoryTest {
@Autowired
PostsRepository postsRepository;
@After //단위 테스트 끝날때 작동 데이터 침범을 막기위해 .
public void cleanup() {
postsRepository.deleteAll();
}
@Test
public void 게시글저장_불러오기() {
String title = "게시글 제목";
String content = "게시글 본문";
postsRepository.save(Posts.builder() //save 기능은 insert/update id가 잇으면 업데이트를 실행한다.
.title(title)
.content(content)
.author("kkkj@naver.com")
.build()
);
List<Posts> postsList = postsRepository.findAll();
Posts posts = postsList.get(0);
assertThat(posts.getTitle()).isEqualTo(title);
assertThat(posts.getContent()).isEqualTo(content);
}
@Test
public void 베이스엔티티_등록() {
//given
LocalDateTime now = LocalDateTime.of(2021, 9, 25, 0, 0, 0);
postsRepository.save(Posts.builder().title("title").content("content").author("author").build());
//when
List<Posts> postsList = postsRepository.findAll();
//then
Posts posts = postsList.get(0);
System.out.println(">>>>>>>>>> createDate=" + posts.getCreatedDate() );
System.out.println(">>>>>>>>>> modifyDate=" + posts.getModifiedDate() );
assertThat(posts.getCreatedDate()).isAfter(now);
assertThat(posts.getModifiedDate()).isAfter(now);
}
}
테스트코드.
여기까지 -> 테이블과 링크할수있는 엔티티 / 레파지토리를 만든후 코드생성후 테스트 함.