목차
Entity
Entity Class
- @Entity : 데이터베이스의 테이블과 매핑되는 객체라는 선언.
- @Table(name = “”) : 테이블 이름과 클래스 이름이 다를 때 사용.
Entity Properties
- @id : primary key로 사용할 속성
- @GeneratedValue(strategy = ) : 자동으로 값 생성
- GenerationType.AUTO : (default) DBMS를 보고 JPA가 알아서 결정(오라클 : 시퀀스)
- GenerationType.IDENTITY : DBMS가 생성, Auto increment
- GenerationType.SEQUENCE : DB의 sequence 사용
- @Column : property는 해당 이름으로 컬럼이 생성되는데 추가 정보를 정의한다.
- name = “ ” : 변수 이름과 별개로 Column 이름을 지정
- insertable / updateble = true / false : Entity 저장 / 수정 시 해당 컬럼도 저장 하는가 ?
- nullable = true / false : null 허용 여부
- unique = true / false
- length = 255 , 컬럼 길이
- precision, scale = 전체 자릿수, 소수 자릿수
- @Transiend : Java 객체에서는 사용하지만 Table 컬럼과는 매핑하지 않을 속성
- @Temporal(TYPE) : Java의 Date, LocalDateTime, Calendar 등을 데이터베이스 타입으로 변환
- TemporalType.DATE : 날짜만
- TemporalType.TIME : 시간만
- @Temporal 을 생략하면 timestamp로
- @Relationship
- Foreign key를 가지는 쪽이 관계의 주인이라 생각하면 된다.
- 관계의 주인 - insert, update를 할 수 있다
- @OneToOne(option)
- optional = true / false
- 두 테이블 중 Foreign key를 만들지 않을 곳에 mappedBy(read-only)를 추가한다.
- @OneToOne(mappedBy=”user”)
- @ManyToOne : 1:N의 관계
- @JoinColumn(name=””) 로 foreign key로 사용할 컬럼을 지정할 수 있다.
- 한 Entity가 다른 Entity를 @ManyToOne으로 만 지정해도 Many에 해당하는 Entity 쿼리 시 Join이 일어난다.
- @OntToMany
- ManyToOne의 One에 해당하는 Entity에 관련 리스트를 조회할 용도로 많이 사용한다.
- mappedBy를 정의해 read-only로 해당 값을 읽어가도록 한다.
Entity Manager
Entity Manager
엔티티를 누가 만드는 가? → Entity Manager
- 데이터베이스와 애플리케이션 사이에서 객체를 관리
- Entity Factory에서 필요한 Entity Manager 객체를 생성.
- 같은 테이블에 대해 동시에 여러 개의 요청이 발생할 경우 Factory에서 여러 Manager를 생성하여 각각 처리
각 Entity Manager는 Persistence Context (영속성 컨텍스트) 라는 메모리 공간을 가진다.
- 1차 캐시 @Id 로 구별되는 객체들을 보관한다. Entity를 조회하면 1차 캐시에서 먼저 찾아보고 있으면 반환 없으면 데이터베이스에서 조회 후 캐시에 저장하고 반환
- 쓰기 지연 Transaction commit 전에는 실제 데이터베이스에 쿼리하지 않고 commit 시에 한번에 실행.
- 변경 감지 Transaction이 commit 되면 1차 캐시의 값과 현재 값을 비교하여 변경된 값이 있다면 데이터베이스에 반영. save() 함수로 업데이트를 수정할 수 있는 이유.
- 지연 로딩 쿼리로 요청한 데이터를 필요할 때 조회함
즉시 로딩과 지연 로딩
- ManyToOne, OneToMany
- 테이블간의 Relation이 있을 때 어떻게 로딩할 것인가?
- ManyToOne
- 게시글 - 작성자 같은 관계. 이 경우 게시글을 조회하면 사용자 정보도(조인 연산으로) 즉시 조회된다.
- OneToMany
- 작성자 - 게시글 의 관계. 이 경우 사용자 정보는 즉시 조회하지만 게시글 리스트는 쿼리되지 않은 상태(프록시)이며, user.getPosts( ) 와 같이 user 객체를 통해 게시글을 조회할 때 쿼리가 실행된다.
- ManyToOne
- 기본 값이 즉시 로딩 FetchType.EAGER
- OneToMany
- 사용자 정보를 쓸 때 마다 매번 게시글 목록을 본다면 즉시 로딩 FetchType.EAGER
- 사용자 정보를 쓸 때 가끔 게시글 목록을 본다면 지연 로딩 FetchType.LAZY
Entity Manager
- EntityManager를 직접 생성해야 하나?
- Spring-data-jpa에서 관리하므로 직접 생성할 필요는 없다.
- Spring을 쓰는 동안에는 굳이 생각을 할 필요가 없다.
- 매번 commit 해야 하나? → 디폴트가 auto commit이다.
- application.properties 에서 속성을 정할 수 있는데 기본적으로 auto commit 이다.
- 여러 개의 SQL을 하나의 Transaction으로 처리하려면 auto commit 을 꺼야한다.
Repository
- Spring Data Jpa 에서 제공하는 interface
- public interface MyRepository extends Repository<Entity, KeyType>
- 개발자가 반복적인 코드를 덜 할 수 있도록 해준다.
- Method 이름을 이용해 SQL Query 를 생성한다.
- Paging, Sort 등은 파라미터를 통해 설정한다.
- find : select 문 예시
- save : 저장 또는 업데이트
- 다음 코드는 객체가 생성되었지만 Entity Manager는 이 객체의 존재를 모른다.
Lecture lecture = new Lecture();
- 다음과 같이 save 할 때
Lecture lecture = new Lecture();
Lecture savedLecture = lectureRepository.save(lecture);
-
- @Id 필드가 null 이면 새 데이터라 생각하고 영속성 컨텍스트에 객체를 추가한 다음 참조를 return한다. (lecture != savedLecture)
- @Id 필드가 null 이 아닌데 영속성 컨텍스트에는 없을 때 merge 동작 → 1차 캐시에서 찾아보고 없으면 DB에 쿼리
- @Id 필드에 해당되는 객체가 영속성 컨텍스트에 있을 때 → update
복잡한 쿼리 사용
@Query 를 사용하는 방법
@Query(value="select * from lecture", nativeQuery=true)
public List<Lecture> selectAll();
-
- value에 sql을 작성하고 nativeQuery = true 로 하면 직접 작성한 쿼리를 수행할 수 있다.
- 가변 부분은 : 변수 이름으로 SQL문에 추가할 수 있으며 @Param으로 설정한다.
- nativeQuery 가 선언되지 않으면 SQL 문이 아닌 JPQL 문법을 따르므로 주의한다.
- JPQL 문법은 컬럼 이름이 Entity의 변수이름, Table명은 Entity의 클래스명 이러한 형식을 사용함
- @Query를 사용하는 방법 : Join
- 만약 Join을 사용하면 Entity 클래스에 정의된 구조와 결과값을 받아오는 구조가 다른데 이에 대해 새로운 클래스를 만들어도 되고, DTO에 결과를 받을 인터페이스를 정의해도된다.
package com.example.myschool.lecture.dto;
public interface LectureWithTeacherName {
public Integer getLectureId();
public String getTitle();
public Integer getTeacherId();
public String getTeacherName();
public String getDescription();
}
→ Dto : 결과를 받을 interface를 DTO에 정의
public interface LectureRepository extends JpaRepository<Lecture, Integer>{
@Query(value="select l.lecture_id as lectureId, l.title, l.teacher_id as teacherId,"+
" l.description , t.name as teacherName from lecture as l "+
"left join teacher as t on l.teacher_id=t.teacher_id", nativeQuery=true)
public List<LectureWithTeacherName> selectAll();
}
→ Repository : Query문 정의 및 메소드 정의
Spring에서 DB 사용
JPA
- Entity Class 선언
- SQL → 함수 이름 또는 @Query
MyBatis
- 데이터를 받거나 집어넣을 Class 선언 → MyBatis에서 부르는 이름 : Mapper class 라고 부름
- SQL → src/resource 폴더 하위에 xml 파일로 작성 또는 @Query
- 엄청 긴 코드를 쓸 때 조금 더 편하게 사용할 수 있다.
Entity
Entity Class
- @Entity : 데이터베이스의 테이블과 매핑되는 객체라는 선언.
- @Table(name = “”) : 테이블 이름과 클래스 이름이 다를 때 사용.
Entity Properties
- @id : primary key로 사용할 속성
- @GeneratedValue(strategy = ) : 자동으로 값 생성
- GenerationType.AUTO : (default) DBMS를 보고 JPA가 알아서 결정(오라클 : 시퀀스)
- GenerationType.IDENTITY : DBMS가 생성, Auto increment
- GenerationType.SEQUENCE : DB의 sequence 사용
- @Column : property는 해당 이름으로 컬럼이 생성되는데 추가 정보를 정의한다.
- name = “ ” : 변수 이름과 별개로 Column 이름을 지정
- insertable / updateble = true / false : Entity 저장 / 수정 시 해당 컬럼도 저장 하는가 ?
- nullable = true / false : null 허용 여부
- unique = true / false
- length = 255 , 컬럼 길이
- precision, scale = 전체 자릿수, 소수 자릿수
- @Transiend : Java 객체에서는 사용하지만 Table 컬럼과는 매핑하지 않을 속성
- @Temporal(TYPE) : Java의 Date, LocalDateTime, Calendar 등을 데이터베이스 타입으로 변환
- TemporalType.DATE : 날짜만
- TemporalType.TIME : 시간만
- @Temporal 을 생략하면 timestamp로
- @Relationship
- Foreign key를 가지는 쪽이 관계의 주인이라 생각하면 된다.
- 관계의 주인 - insert, update를 할 수 있다
- @OneToOne(option)
- optional = true / false
- 두 테이블 중 Foreign key를 만들지 않을 곳에 mappedBy(read-only)를 추가한다.
- @OneToOne(mappedBy=”user”)
- @ManyToOne : 1:N의 관계
- @JoinColumn(name=””) 로 foreign key로 사용할 컬럼을 지정할 수 있다.
- 한 Entity가 다른 Entity를 @ManyToOne으로 만 지정해도 Many에 해당하는 Entity 쿼리 시 Join이 일어난다.
- @OntToMany
- ManyToOne의 One에 해당하는 Entity에 관련 리스트를 조회할 용도로 많이 사용한다.
- mappedBy를 정의해 read-only로 해당 값을 읽어가도록 한다.
Entity Manager
Entity Manager
엔티티를 누가 만드는 가? → Entity Manager
- 데이터베이스와 애플리케이션 사이에서 객체를 관리
- Entity Factory에서 필요한 Entity Manager 객체를 생성.
- 같은 테이블에 대해 동시에 여러 개의 요청이 발생할 경우 Factory에서 여러 Manager를 생성하여 각각 처리
각 Entity Manager는 Persistence Context (영속성 컨텍스트) 라는 메모리 공간을 가진다.
- 1차 캐시 @Id 로 구별되는 객체들을 보관한다. Entity를 조회하면 1차 캐시에서 먼저 찾아보고 있으면 반환 없으면 데이터베이스에서 조회 후 캐시에 저장하고 반환
- 쓰기 지연 Transaction commit 전에는 실제 데이터베이스에 쿼리하지 않고 commit 시에 한번에 실행.
- 변경 감지 Transaction이 commit 되면 1차 캐시의 값과 현재 값을 비교하여 변경된 값이 있다면 데이터베이스에 반영. save() 함수로 업데이트를 수정할 수 있는 이유.
- 지연 로딩 쿼리로 요청한 데이터를 필요할 때 조회함
즉시 로딩과 지연 로딩
- ManyToOne, OneToMany
- 테이블간의 Relation이 있을 때 어떻게 로딩할 것인가?
- ManyToOne
- 게시글 - 작성자 같은 관계. 이 경우 게시글을 조회하면 사용자 정보도(조인 연산으로) 즉시 조회된다.
- OneToMany
- 작성자 - 게시글 의 관계. 이 경우 사용자 정보는 즉시 조회하지만 게시글 리스트는 쿼리되지 않은 상태(프록시)이며, user.getPosts( ) 와 같이 user 객체를 통해 게시글을 조회할 때 쿼리가 실행된다.
- ManyToOne
- 기본 값이 즉시 로딩 FetchType.EAGER
- OneToMany
- 사용자 정보를 쓸 때 마다 매번 게시글 목록을 본다면 즉시 로딩 FetchType.EAGER
- 사용자 정보를 쓸 때 가끔 게시글 목록을 본다면 지연 로딩 FetchType.LAZY
Entity Manager
- EntityManager를 직접 생성해야 하나?
- Spring-data-jpa에서 관리하므로 직접 생성할 필요는 없다.
- Spring을 쓰는 동안에는 굳이 생각을 할 필요가 없다.
- 매번 commit 해야 하나? → 디폴트가 auto commit이다.
- application.properties 에서 속성을 정할 수 있는데 기본적으로 auto commit 이다.
- 여러 개의 SQL을 하나의 Transaction으로 처리하려면 auto commit 을 꺼야한다.
Repository
- Spring Data Jpa 에서 제공하는 interface
- public interface MyRepository extends Repository<Entity, KeyType>
- 개발자가 반복적인 코드를 덜 할 수 있도록 해준다.
- Method 이름을 이용해 SQL Query 를 생성한다.
- Paging, Sort 등은 파라미터를 통해 설정한다.
- find : select 문 예시
- save : 저장 또는 업데이트
- 다음 코드는 객체가 생성되었지만 Entity Manager는 이 객체의 존재를 모른다.
Lecture lecture = new Lecture();
- 다음과 같이 save 할 때
Lecture lecture = new Lecture();
Lecture savedLecture = lectureRepository.save(lecture);
-
- @Id 필드가 null 이면 새 데이터라 생각하고 영속성 컨텍스트에 객체를 추가한 다음 참조를 return한다. (lecture != savedLecture)
- @Id 필드가 null 이 아닌데 영속성 컨텍스트에는 없을 때 merge 동작 → 1차 캐시에서 찾아보고 없으면 DB에 쿼리
- @Id 필드에 해당되는 객체가 영속성 컨텍스트에 있을 때 → update
복잡한 쿼리 사용
@Query 를 사용하는 방법
@Query(value="select * from lecture", nativeQuery=true)
public List<Lecture> selectAll();
-
- value에 sql을 작성하고 nativeQuery = true 로 하면 직접 작성한 쿼리를 수행할 수 있다.
- 가변 부분은 : 변수 이름으로 SQL문에 추가할 수 있으며 @Param으로 설정한다.
- nativeQuery 가 선언되지 않으면 SQL 문이 아닌 JPQL 문법을 따르므로 주의한다.
- JPQL 문법은 컬럼 이름이 Entity의 변수이름, Table명은 Entity의 클래스명 이러한 형식을 사용함
- @Query를 사용하는 방법 : Join
- 만약 Join을 사용하면 Entity 클래스에 정의된 구조와 결과값을 받아오는 구조가 다른데 이에 대해 새로운 클래스를 만들어도 되고, DTO에 결과를 받을 인터페이스를 정의해도된다.
package com.example.myschool.lecture.dto;
public interface LectureWithTeacherName {
public Integer getLectureId();
public String getTitle();
public Integer getTeacherId();
public String getTeacherName();
public String getDescription();
}
→ Dto : 결과를 받을 interface를 DTO에 정의
public interface LectureRepository extends JpaRepository<Lecture, Integer>{
@Query(value="select l.lecture_id as lectureId, l.title, l.teacher_id as teacherId,"+
" l.description , t.name as teacherName from lecture as l "+
"left join teacher as t on l.teacher_id=t.teacher_id", nativeQuery=true)
public List<LectureWithTeacherName> selectAll();
}
→ Repository : Query문 정의 및 메소드 정의
Spring에서 DB 사용
JPA
- Entity Class 선언
- SQL → 함수 이름 또는 @Query
MyBatis
- 데이터를 받거나 집어넣을 Class 선언 → MyBatis에서 부르는 이름 : Mapper class 라고 부름
- SQL → src/resource 폴더 하위에 xml 파일로 작성 또는 @Query
- 엄청 긴 코드를 쓸 때 조금 더 편하게 사용할 수 있다.