바로 실습으로 진행해보자!
위와 같이 프로젝트를 생성한다.
그리고 mysql workbench에서 새로운 유저와 새로운 스키마를 만든다. 스키마 이름은 demo_jpa_schema 로 했다.
유저이름은 demo_jpa로 만들었다.
그리고 권한 설정을 해준다. Schema Privileges 에서 add entry버튼을 누른다.
그리고 select all 버튼을 누른 후 apply 버튼을 누른다.
그리고 다시 새로운 커넥션을 만들고 아래에 만들어줬던 스키마와 유저에 대한 정보를 입력한다.
그리고 이제 위에 설정한 정보들을 프로젝트에 작성해주자!
기존에 프로젝트 내에 있었던 applcaton.properties를 지우고 application.yml 파일을 만들고 아래와 같이 작성한다.
뭐를 뜻하는거지?
- hibernate : 지난 글에서 설명했음!
- ddl-auto : 테이블을 생성하고 제거를 하는 과정을 자동으로해주는 옵션이다. 통상적으로는 none으로 사용하는데 연습용도 이기 때문에 create로 설정
- show-sql : jpa가 작동하면서 실제로 실행 하게되는 sql문을 보여줄지 말지를 정하는 설정
- dialect : mysql을 사용하니까 참고하라고 hibernate에게 알려주는 것
그리고 프로젝트를 실행시키면 아래와 같이 오류가 없는 것을 확인할 수 있다. -> 초기설정 끝!
ddl-option
- create: 기존테이블 삭제 후 다시 생성 (DROP + CREATE)
- create-drop: create와 같으나 종료시점에 테이블 DROP
- update: 변경분만 반영(운영DB에서는 사용하면 안됨)
- validate: 엔티티와 테이블이 정상 매핑되었는지만 확인
- none: 사용하지 않음(사실상 없는 값이지만 관례상 none이라고 한다.)
주의할 점- 운영 장비에서는 절대 create, create-drop, update 사용하면 안된다.
- 개발 초기 단계는 create 또는 update
- 테스트 서버는 update 또는 validate
- 스테이징과 운영 서버는 validate 또는 none
그리고 아래와 같이 패키지와 클래스를 만든다.
이제 안에 내용을 작성해보자.
먼저 PostEntity.java파일을 작성한다. 기본키를 자동으로 생성할 때에는 @Id와 @GenerratedValue 어노테이션이 함께 사용되어야 한다. 생성자, Getter/Setter, toString 도 함께 작성해준다.
@GenerratedValue과 관련하여 프라이머리키를 자동으로 생성하는 방법 4가지가 있는데 각각의 방법들에 대해서는 구글링을 해보자..
위처럼 작성이 끝나고 프로젝트를 실행시킨 후 workbench로 들어가서 왼쪽 Schemas 부분에 작게 있는 새로고침 버튼을 누르면 아주 기게 막히게 테이블이 생성된 것을 볼 수 있다.
jpa hibernate는 위에서와 같이 자신이 원하는 객체에 특정한 설정을 줌으로써 테이블의 형태로 작성되는 것을 알 수 있다.
다음으로 BoardEntity.java 부분을 작성해보자. 위와 비슷한 방법으로 만들어주고 마찬가지로 생성자, Getter/Setter, toString 도 함께 작성해준다.
Board는 여러 개의 Post를 가지고 있는 관계이다. 이 부분을 설정해주기 위해 PostEntity.java에 아래와 같이 추가로 작성한다.
다대일 관계 - Board는 여러 개의 Post를 가지고 있다. Board 관점에서 자신은 많고 Post는 하나이니까 다대다라고 생각하면 될 것 같다.
그러고 프로젝트를 실행해보면 경고가 나온다.
PostEntity에 BoardEntity가 추가 되었고 그것을 적용하기 위해서 하이버네이트가 작동이 되면 PostEntity의 foreign키는 BoardEntity의 Primary 키를 가리키게 된다.
그런데 BoardEntity는 방금 생성이 되었기 때문에 PostEntity에서 foreign키가 존재하지 않게 된다.
따라서 drop을 할 수 없기 때문에 문제가 생기는 것이다. -> 지금 바로 큰 문제가 있는 것은 아니다.
(검색을 해보니 ddl과 관련이 있어보이는데 자세한 부분은 좀 더 공부를 해봐야겠다..)
아래는 경고 문구
2022-03-02 03:23:54.602 WARN 19736 --- [ main] o.h.t.s.i.ExceptionHandlerLoggedImpl : GenerationTarget encountered exception accepting command : Error executing DDL "alter table post_entity drop foreign key FKaxuu0ckhfr1ome9hmeevkg7oc" via JDBC Statement
workbench 상에서 새로고침을 해보면 아래와 같이 이상없이 작성된 것을 알 수 있다. foreign키가 자동으로 생성되었다.
mappedBy란?
위에 작성한 것이 PostEntity.java에도 한 번 작성이 되어있다. (@ManyToOne으로) mappedBy 가 없다면 BoardEntity.java 에서 작성한 @OneToMany와 PostEntity.java에서 작성한 @ManyToOne이 다른 관계로 인식할 수 있기 때문에 이를 방지하고자 작성한다.
위에서는 PostEntity.java에 있는 자료형이 BoardEntity인 변수명인 boardEntity를 적어주면 된다.
fetch
JPA에서는 데이터를 조회할 때 즉시 로딩(EAGER)과 지연 로딩(LAZY) 두 가지 방식이 있다. 이 두 가지 방식을 간단하게 설명하면 즉시 로딩은 데이터를 조회할 때 연관된 데이터까지 한 번에 불러오는 것이고, 지연 로딩은 필요한 시점에 연관된 데이터를 불러오는 것이라고 할 수 있다.
가급적이면 기본적으로 지연 로딩을 사용하는 것이 좋다.
여기까지 테이블 관련된 코드를 완료하였고, 이제 레포지토리쪽을 작성해보자.
특정 유형의 저장소에서 일반 CRUD 작업을 위한 인터페이스인 CrudRepository를 extends한다. 먼저 BoardRepository.java를 작성하고
형식: CrudRepository<타겟으로 하는 엔티티, 그 엔티티의 아이디 자료형>
마찬가지로 PostRepository.java도 작성해보자.
이렇게 작성하면 기초적인 기능들을 사용할 수 있다. 예시를 들어보자. 아래와 같이 테스트 자바 파일을 작성하였고
18번째 줄, 25번째 줄 처럼 사용한 이유는?
주어진 엔티티를 저장하고 저장 작업이 엔터티 인스턴스를 완전히 변경했을 수 있으므로 추가 작업에 반환된 인스턴스를 사용하라고 공식 문서에 나와 있기 때문..!
프로젝트를 실행시킨 후 workbench에서 확인해보면 문제없이 자료가 생성된 것을 확인할 수 있다.
우리가 작성한 Repository는 CrudRepository인터페이스를 상속받았기 때문에 아래와 같이 많은 기능을 사용할 수 있다.
이런 기본적인 기능들 이외에 추가적인 기능을 만들어보자.
놀랍게도 이렇게 메소드 이름만으로도 기능이 구현된다.
기존 테스트 클레스에
System.out.println(postRepository.findAllByWriter("khs").size());
와 같이 입력하면 콘솔창에 1이 뜨는 것을 확인할 수 있다.
기본적으로 메소드 이름을 짓는 문법 방법은 구글링을 하다가 정리를 잘 해주신 분이 있어 여기를 참고하기를 바란다.
아래와 같이 활용도 가능하다.
이제 몇가지만 더 해보고 마무리하자. 아까 위에서 만들어놓은 BaseEntity.java는 어떻게 사용하면 될까.
만약에 모든 엔티티들이 가져야하는 속성에 대해 정의하고 싶다면 @MappedSuperclass 라는 어노테이션을 붙여주고 아래와 같이 작성하면 된다.
그리고 이 추상 클래스를 각각의 엔티티에 extends 해주면 된다.
그리고 메인 클레스에 @EnableJpaAuditing 를 붙여주면 된다.
프로젝트를 실행하고 워크벤치를 새로고침한다면
컬럼들이 새로 추가된 것을 확인할 수 있다.
위 사진을 보면 테이블 이름이 이쁘지 않은데 어노테이션을 추가해서 테이블 이름을 수정할 수 있다.
그리고
컬럼 이름도 바꿔줄 수 있다.
PostEntity.java내에서 작성 | BoardEntity.java내에서 작성 |
위와 같이 작성하고 워크벤치에서 확인해보면
위와 같이 나오 것을 확인할 수 있다. (ddl 설정에서 create로 했기 때문에 기존 테이블이 drop 되지 않은 듯 하다.. 강의에서 그렇게 진행했기 때문에 따로 수정은 하지 않겠다.)