참고 URL : https://victorydntmd.tistory.com/323?category=764331
https://zeroco.tistory.com/44
https://github.com/jojoldu/freelec-springboot2-webservice/issues/67
https://jforj.tistory.com/83
https://mangkyu.tistory.com/20
https://careerly.co.kr/comments/82539?utm_campaign=user-share
https://tech.onepredict.ai/4367923e-8e13-407c-8845-67d270d324d7
출처 : https://velog.io/@rladuswl/ORM%EC%9D%98-%EA%B0%9C%EB%85%90-JPA%EC%99%80-MyBatis-%EC%B0%A8%EC%9D%B4
ORM은 객체와 DB테이블을 매핑시켜 RDB테이블을 객체 지향적으로 사용할수 있도록 해주는 기술입니다.
JPA 는 JAVA의 ORM( Object Relational Mapping ) 기술 표준입니다.
Hibernate는 자바 언어를 위한 ORM 프레임워크입니다.
JPA는 CRUD 메소드를 기본적으로 제공하며 쿼리를 직접 만들지 않아도 됩니다.
MYbatis 는 쿼리가 수정되어 데이터 정보가 바뀌면 그에 사용하고 있던 DTO도 같이 수정해야 하는 반면 JPA는 객체만 변경하면 됩니다.
객체(Object)와 DB의 테이블을 Mapping 시켜 RDB 테이블을 객체지향적으로 사용하게 해주는 기술
객체와 RDB를 별개로 설계하고 중간에서 ORM이 매핑해주는 역할을 한다. 즉, ORM은 SQL문이 아닌 RDB의 데이터 그 자체와 매핑하기 때문에 SQL을 직접 작성하지 않는다.
여기서 RDB 테이블이란, 관계형 데이터베이스를 말한다. 참고
RDB 테이블은 객체지향적 특성(상속, 다형성, 레퍼런스) 등이 없어서 Java와 같은 객체 지향적 언어로의 접근이 쉽지 않다.
이럴때 ORM을 사용하면 보다 객체지향적으로 RDB를 사용할 수 있다!
Java에서 사용하는 대표적인 ORM으로는 JPA와 그의 구현체 Hibernate가 있다. JPA가 등장하기 전에는 위에 설명했듯이 MyBatis라는 Object Mapping 기술을 이용하였는데, MyBatis는 Java 클래스 코드와 직접 작성한 SQL 코드를 매핑 시켜주어야 했다.
하지만! JPA와 같은 ORM기술은 객체가 DB에 연결되기 때문에 SQL을 직접 작성하지 않는다.
따라서 JPA라는 ORM 기술에 의해 DB에서 조회한 데이터들이 객체로 연결되어 있고, 객체의 값을 수정하는 것은 DB의 값을 수정하는 것이라고 할 수 있다.
생산성: SpringBoot JPA는 ORM(Object-Relational Mapping)을 사용하므로 개발자는 SQL 쿼리를 직접 작성하지 않아도 됩니다.
이는 개발 생산성을 높이고 코드 작성 시간을 줄입니다.
유지보수성: SpringBoot JPA는 데이터베이스 스키마와 일치하는 도메인 모델을 생성할 수 있으므로 데이터베이스 스키마 변경 시 도메인 모델만 업데이트하면 됩니다.
이는 유지보수성을 높이고 데이터베이스 스키마 변경에 따른 영향을 최소화합니다.
성능: SpringBoot JPA는 내부적으로 캐시를 사용하여 반복적인 쿼리를 최적화합니다.
이는 애플리케이션의 성능을 높이고 데이터베이스 부하를 줄입니다.
테스트 용이성: SpringBoot JPA는 인메모리 데이터베이스를 지원하므로 개발자는 데이터베이스 설정 없이 테스트를 수행할 수 있습니다.
또한, SpringBoot JPA는 모의 객체(Mock Object)를 생성하는 기능을 제공하여 테스트 용이성을 높입니다.
다양한 데이터베이스 지원: SpringBoot JPA는 다양한 데이터베이스를 지원합니다.
따라서 개발자는 동일한 코드베이스를 사용하여 다양한 데이터베이스에 대해 애플리케이션을 빌드할 수 있습니다.
Entity Class Package :
JPA에서 사용하는 Entity 클래스들을 저장하는 패키지입니다.
패키지 이름은 보통 "domain" 또는 "model"과 같은 이름으로 작성합니다.
각 엔티티 클래스는 테이블과 매핑됩니다.
Repository Class Package :
JPA에서 사용하는 Repository 클래스들을 저장하는 패키지입니다.
패키지 이름은 보통 "repository"와 같은 이름으로 작성합니다.
각 Repository 클래스는 데이터베이스와의 상호작용을 담당합니다.
Service Class Package :
비즈니스 로직을 담당하는 서비스 클래스들을 저장하는 패키지입니다.
패키지 이름은 보통 "service"와 같은 이름으로 작성합니다.
각 서비스 클래스는 하나 이상의 Repository 클래스를 사용하여 데이터베이스와 상호작용합니다.
Domain : 비즈니스 도메인을 나타내는 개념
Domain은 비즈니스의 핵심 도메인을 나타내는 객체들의 집합입니다.
예를 들어, 인터넷 쇼핑몰에서의 "상품", "주문", "고객" 등이 비즈니스 도메인에 해당합니다.
이러한 도메인 객체들은 애플리케이션에서 사용되며, 비즈니스 로직을 구현하기 위해 필요한 속성과 메서드를 가지고 있습니다.
Entity : 데이터베이스에 저장되는 개체를 나타내는 개념
Entity는 데이터베이스에서 관리되는 객체를 나타내는 개념입니다.
JPA에서 Entity는 데이터베이스의 테이블과 매핑되며, 데이터베이스의 각 행은 Entity의 인스턴스에 해당합니다.
따라서 Entity는 데이터베이스의 데이터를 객체 지향적으로 다루기 위한 개념이며, 데이터베이스에서 데이터를 가져와 애플리케이션에서 사용할 수 있는 형태로 변환합니다.
JPA에서는 Domain 객체와 Entity 간의 매핑을 통해 데이터베이스와 애플리케이션 간의 변환을 수행합니다. 이를 통해 애플리케이션 개발자는 데이터베이스를 직접 다루는 복잡한 코드를 작성하지 않아도 됩니다.
@Entity : JPA 엔티티 클래스를 선언할 때 사용합니다.
JPA는 @Entity가 선언된 클래스를 자동으로 관리하게 됩니다.
@Id : 엔티티 클래스의 기본키(PK) 필드를 나타냅니다.
이 어노테이션이 선언된 필드는 해당 엔티티의 식별자로 사용됩니다.
@GeneratedValue : 기본키 값을 자동으로 생성할 때 사용됩니다.
JPA에서는 대표적으로 IDENTITY, SEQUENCE, TABLE 전략을 제공합니다.
@Column : 엔티티 클래스의 속성(필드)을 나타냅니다.
데이터베이스 테이블에 매핑할 때 속성의 이름, 데이터 타입, 길이 등을 설정할 수 있습니다.
@OneToOne, @OneToMany, @ManyToOne, @ManyToMany : 이러한 어노테이션은 엔티티 간의 관계를 나타냅니다.
예를 들어, @OneToOne은 일대일 관계를, @OneToMany는 일대다 관계를, @ManyToOne은 다대일 관계를, @ManyToMany는 다대다 관계를 나타냅니다.
@JoinColumn : 엔티티 간의 관계를 매핑할 때 사용됩니다.
외래 키(FK)를 나타냅니다.
@Transient : 엔티티 클래스에서 매핑하지 않을 필드를 나타냅니다.
이 어노테이션이 선언된 필드는 데이터베이스 테이블에 매핑되지 않습니다.
@Temporal : 날짜 및 시간 타입(Date, Calendar)을 매핑할 때 사용됩니다.
데이터베이스 컬럼의 타입을 지정합니다.
@Version : 엔티티 클래스에서 버전 관리를 위해 사용됩니다.
엔티티가 업데이트될 때마다 버전 값을 증가시키며, 이를 통해 동시성 제어를 수행합니다.
save(S entity): 엔티티를 저장합니다. 새로운 엔티티인 경우에는 새로운 엔티티를 추가하고, 기존 엔티티인 경우에는 업데이트를 수행합니다.
deleteById(ID id): 지정된 ID 값을 가진 엔티티를 삭제합니다.
findById(ID id): 지정된 ID 값을 가진 엔티티를 조회합니다.
findAll(): 모든 엔티티를 조회합니다.
count(): 엔티티의 총 개수를 반환합니다.
existsById(ID id): 지정된 ID 값을 가진 엔티티가 존재하는지 여부를 반환합니다.
flush(): 변경된 내용을 즉시 데이터베이스에 적용합니다.
saveAll(Iterable<S> entities): 여러 개의 엔티티를 저장합니다.
deleteAll(): 모든 엔티티를 삭제합니다.
deleteInBatch(Iterable<T> entities): 여러 개의 엔티티를 삭제합니다.
findAllById(Iterable<ID> ids): 주어진 ID 값들을 가진 엔티티들을 조회합니다.
delete(T entity): 엔티티를 삭제합니다.
deleteAllInBatch(): 모든 엔티티를 일괄 삭제합니다.
findAll(Sort sort): 모든 엔티티를 정렬하여 조회합니다.
findAll(Pageable pageable): 페이지네이션 및 정렬된 엔티티를 조회합니다.
flush(): 변경된 내용을 데이터베이스에 즉시 적용합니다.
deleteAllById(Iterable<ID> ids): 주어진 ID 값들을 가진 엔티티들을 일괄 삭제합니다.
deleteAll(Iterable<? extends T> entities): 주어진 엔티티들을 일괄 삭제합니다.
deleteAllByIdInBatch(Iterable<ID> ids): 주어진 ID 값들을 가진 엔티티들을 일괄 삭제합니다. 이 메서드는 일괄 처리(batch processing) 기능을 사용하여 삭제 작업을 수행합니다.
deleteAllInBatch(Iterable<T> entities): 주어진 엔티티들을 일괄 삭제합니다. 이 메서드는 일괄 처리(batch processing) 기능을 사용하여 삭제 작업을 수행합니다.
findAll(Example<S> example): 주어진 예제(Example)를 만족하는 엔티티들을 조회합니다. 예제를 사용하면 엔티티의 여러 속성을 기반으로 검색할 수 있습니다.
findAll(Example<S> example, Sort sort): 주어진 예제(Example)를 만족하는 엔티티들을 정렬하여 조회합니다.
findOne(Example<S> example): 주어진 예제(Example)를 만족하는 단일 엔티티를 조회합니다.
saveAndFlush(S entity): 엔티티를 저장하고 변경 내용을 데이터베이스에 즉시 적용합니다.
saveAllAndFlush(Iterable<S> entities): 여러 개의 엔티티를 저장하고 변경 내용을 데이터베이스에 즉시 적용합니다.
exists(Example<S> example): 주어진 예제(Example)를 만족하는 엔티티가 존재하는지 여부를 반환합니다.
참고링크 : https://private-space.tistory.com/87
https://developer-youngjun.tistory.com/21
https://gofnrk.tistory.com/58
findAll(Specification<T> spec, Pageable pageable): 주어진 조건(Specification)에 따라 엔티티를 조회하고, 페이징(Paging) 처리를 수행합니다.
Specification은 검색 조건을 표현하는 객체로, JPA Criteria API를 사용하여 생성할 수 있습니다. 이 메서드를 사용하면 다수의 엔티티 간의 조인을 처리할 수 있습니다.
findAll(Specification<T> spec, Sort sort): 주어진 조건(Specification)에 따라 엔티티를 조회하고, 정렬(Sort) 처리를 수행합니다.
findAll(Join<T, ?> join): 지정된 Join 객체를 사용하여 엔티티를 조회합니다.
Join 객체는 JPA Criteria API를 사용하여 생성할 수 있으며, 여러 개의 조인을 처리할 수 있습니다.
findAll(Join<T, ?> join, Specification<T> spec): 주어진 조건(Specification)에 따라 Join 객체를 사용하여 엔티티를 조회합니다.
findAll(Join<T, ?> join, Specification<T> spec, Sort sort): 주어진 조건(Specification)과 정렬(Sort)에 따라 Join 객체를 사용하여 엔티티를 조회합니다.
findAll(Join<T, ?> join, Specification<T> spec, Pageable pageable): 주어진 조건(Specification)과 페이징(Paging) 처리에 따라 Join 객체를 사용하여 엔티티를 조회합니다.
findAllBy(Specification<T> spec, Class<R> resultClass, String... selection): 주어진 조건(Specification)에 따라 엔티티를 조회하고,
지정된 결과 클래스(resultClass)와 선택(selection)에 따라 결과를 반환합니다. 이 메서드는 복잡한 조인 쿼리를 처리할 때 유용합니다.
void flush() : 엔티티 매니저의 캐시를 모두 비우고, 변경된 내용을 데이터베이스에 즉시 반영합니다.
T save(S entity) : 주어진 엔티티를 데이터베이스에 저장하거나, 이미 있는 경우에는 업데이트합니다.
Iterable<T> saveAll(Iterable<S> entities) : 주어진 모든 엔티티들을 데이터베이스에 저장하거나, 이미 있는 경우에는 업데이트합니다.
T saveAndFlush(S entity) : 주어진 엔티티를 데이터베이스에 저장하거나, 이미 있는 경우에는 업데이트하고, 이후에는 즉시 flush() 메서드를 호출하여 데이터베이스에 변경 내용을 반영합니다.(변경 내용을 즉시 데이터베이스에 반영)
@Modifying, @Query : JPA에서 제공하는 JPQL(QueryDSL) 또는 Native SQL을 사용하여, 데이터베이스에 직접적인 update 쿼리를 실행하는 메서드입니다.
@Modifying 어노테이션을 사용하여 해당 메서드가 데이터베이스를 수정하는 쿼리임을 명시하고, @Query 어노테이션을 사용하여 실행할 쿼리를 정의합니다.
※ saveAndFlush() 메서드 외에 다른 메서들은 변경 내용을 캐시에 저장한 뒤, flush() 메서드를 호출하여 변경 내용을 데이터베이스에 일괄적으로 반영합니다.
void deleteById(ID id) : 주어진 ID에 해당하는 엔티티를 삭제합니다.
void delete(T entity) : 주어진 엔티티를 삭제합니다.
void deleteAll() : 모든 엔티티를 삭제합니다.
void deleteAll(Iterable<? extends T> entities) : 주어진 모든 엔티티를 삭제합니다.
void deleteInBatch(Iterable<T> entities) : 주어진 모든 엔티티를 데이터베이스에서 삭제합니다. 이 메서드는 삭제 작업을 일괄 처리(batch processing)하여 성능을 향상시킵니다.
void deleteAllInBatch() : 모든 엔티티를 데이터베이스에서 삭제합니다. 이 메서드는 삭제 작업을 일괄 처리(batch processing)하여 성능을 향상시킵니다.
※ 각각의 메서드들은 주어진 인자들을 기반으로 데이터베이스에서 엔티티를 삭제하며, deleteInBatch()와 deleteAllInBatch() 메서드는 일괄 처리(batch processing)하여 성능을 향상시킵니다.
※ JpaRepository에서는 @Query 어노테이션과 함께 Native SQL이나 JPQL(QueryDSL)을 사용하여 직접적인 삭제 쿼리를 실행할 수 있는 메서드도 제공합니다.
이 경우, @Modifying 어노테이션을 함께 사용하여 해당 메서드가 데이터베이스를 수정하는 쿼리임을 명시해주어야 합니다.
<S extends T> S save(S entity) : 주어진 엔티티를 저장하거나 업데이트합니다. 만약 엔티티가 이미 데이터베이스에 존재한다면 업데이트하고, 그렇지 않다면 새로운 엔티티를 생성합니다.
<S extends T> List<S> saveAll(Iterable<S> entities) : 주어진 모든 엔티티를 저장하거나 업데이트합니다. save() 메서드와 달리, saveAll()은 Iterable로 받은 모든 엔티티를 일괄 처리하여 저장합니다.
※ save() 메서드는 단일 엔티티를 저장하거나 업데이트하며, saveAll() 메서드는 Iterable로 받은 모든 엔티티를 일괄 처리하여 저장합니다.
※ JpaRepository에서는 save() 메서드를 호출하지 않아도, 엔티티를 데이터베이스에 자동으로 저장할 수 있는 기능을 제공합니다.
이를 위해 엔티티 클래스에 @Entity 어노테이션과 @Id 어노테이션으로 ID 필드를 명시해주어야 합니다.
그리고, Spring Data JPA에서는 EntityManager를 이용하여 엔티티를 자동으로 저장하는데, 이는 JPA의 영속성 컨텍스트(Persistence Context)를 이용하여 엔티티의 상태를 추적하고,
변경사항이 있을 경우에만 데이터베이스에 자동으로 반영합니다. 이러한 기능을 Dirty Checking이라고 합니다.
SpringBoot : 3.0.5
Gradle : 7.6.1
=================================================================================================================
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.5'
id 'io.spring.dependency-management' version '1.1.0'
}
=================================================================================================================
build.gradle 파일을 열어서 dependencies에 아래의 내용을 추가
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
※ 추가한 라이브러리들
=====================================================================================================================================================
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
=====================================================================================================================================================
=====================================================================================================================================================
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/stock?serverTimezone=UTC&characterEncoding=UTF-8
username: securus
password: securus1234
jpa:
open-in-view: false
show-sql: true
properties :
hibernate:
dialect : org.hibernate.dialect.MySQL57Dialect
storage_engine : innodb
format_sql: true
ddl-auto: validate
logging:
level:
org:
hibernate:
SQL: DEBUG
type:
descriptor:
sql:
BasicBinder: TRACE
server:
port: 9000
=====================================================================================================================================================
* spring.datasource
datasouce는 MySQL 설정과 관련된 것이므로 여기를 참고해주세요.
참고링크 : https://victorydntmd.tistory.com/321
* spring.jpa.database-platform
JPA 데이터베이스 플랫폼을 지정합니다.
* 예제에서는 MySQL InnoDB를 사용하도록 설정했습니다.
* spring.jpa.open-in-view (OSIV - Open Session In View)
웹 요청이 완료될 때까지 동일한 EntityManager를 갖도록 해줍니다.
스프링부트에서 OSIV가 기본값으로 true인데, 성능과 확장상 면에서 안좋다고 해서 false로 설정을 껏습니다. ( 참고 )
참고링크 : https://stackoverflow.com/questions/30549489/what-is-this-spring-jpa-open-in-view-true-property-in-spring-boot
* spring.jpa.show-sql
콘솔에 JPA 실행 쿼리를 출력합니다.
* spring.jpa.hibernate.format_sql
콘솔에 출력되는 JPA 실행 쿼리를 가독성있게 표현합니다.
* spring.jpa.hibernate.ddl_auto
데이터베이스 초기화 전략을 설정합니다.
none
아무것도 실행하지 않습니다.
create
SessionFactory가 시작될 때 기존테이블을 삭제 후 다시 생성합니다.
create-drop
create와 같으나 SessionFactory가 종료될 때 drop을 실행합니다.
update
변경된 스키마만 반영합니다.
validate
엔티티와 테이블이 정상적으로 매핑되었는지만 확인합니다.
logging.level.org.hibernate.type.descriptor.sql
SQL에서 물음표로 표기된 부분( bind parameter )을 로그로 출력해서 확인할 수 있습니다.