스프링

 

 

중급자를 위해 준비한
[웹 개발, 백엔드] 강의입니다.

JPA(Java Persistence API)를 보다 쉽게 사용할 수 있도록 여러 기능을 제공하는 스프링 데이터 JPA에 대해 학습합니다.

✍️
이런 걸
배워요!

ORM에 대한 이해

JPA 프로그래밍

Bean 생성 방법

스프링 JPA가 어렵게 느껴졌다면?
개념과 원리, 실제까지 확실하게 학습해 보세요.

제대로 배우는
백기선의 스프링 데이터 JPA

JPA(Java Persistence API)를 보다 쉽게 사용할 수 있도록 여러 기능을 제공하는 스프링 데이터 JPA에 대해 학습합니다.

 

강의 :

https://www.inflearn.com/course/스프링-데이터-jpa#reviews

 

 

 

강의자료 :

https://docs.google.com/document/d/1IjSKwMEsLdNXhRLvFk576VTR03AKTED_3jMsk0bHANg/edit

 

 

 

소스 코드

https://github.com/braverokmc79/springdatajpa

 

 

 

  1. 강좌 소개

 

Application -> 스프링 데이터 JPA (-> JPA -> JDBC) -> Database

 

 

 

  1. 강사 소개

 

백기선

 

마이크로소프트(2+) <- 아마존(1) <- 네이버(4.5) <- SLT(2.5) ...

 

강좌

  • 스프링 프레임워크 입문 (Udemy)

  • 백기선의 스프링 부트 (인프런)

 

특징

  • 스프링 프레임워크 중독자

  • JPA 하이버네이트 애호가

  • 유튜브 / 백기선

 

 

 

 

 

 

 

[1부: 핵심 개념 이해]

 

 

 

3.관계형 데이터베이스와 자바

 

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13745&tab=community&q=5647&category=questionDetail

 

 

본격적인 스프링 데이터 JPA 활용법을 학습하기에 앞서, ORM과 JPA에 대한 이론적인 배경을 학습합니다. 

 

  1. 관계형 데이터베이스와 자바

 

JDBC

  • (관계형) 데이터베이스와 자바의 연결 고리

JDBC

  • DataSource / DriverManager

  • Connection

  • PreparedStatement

 

SQL

  • DDL

  • DML

 

무엇이 문제인가?

  • SQL을 실행하는 비용이 비싸다.

  • SQL이 데이터베이스 마다 다르다.

  • 스키마를 바꿨더니 코드가 너무 많이 바뀌네...

  • 반복적인 코드가 너무 많아.

  • 당장은 필요가 없는데 언제 쓸 줄 모르니까 미리 다 읽어와야 하나...

 

의존성 추가

        
            org.postgresql
            postgresql
            42.6.0
        

 

PostgreSQL 설치 및 서버 실행 (docker)

 

 

 

docker run -p 5432:5432 -e POSTGRES_PASSWORD=pass -e POSTGRES_USER=keesun -e POSTGRES_DB=springdata --name postgres_boot -d postgres

docker exec -i -t postgres_boot bash

su - postgres

psql springdata

데이터베이스 조회
\list

테이블 조회
\dt

쿼리
SELECT * FROM account;

 

 


★ 윈도우에서 도터 컨테이너 접속후   psql  접속시 다음과 같이 유저명과  DB 명을 입력해야한다.

psql --username keesun --dbname springdata

 

 

 

 

package me.whiteship;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class Application {
    
    public static void main(String[] args) throws  Exception {
        String url ="jdbc:postgresql://localhost:5432/springdata";
        String username="keesun";
        String password="pass";

        try(Connection connection= DriverManager.getConnection(url, username, password)){
            System.out.println("connection = " + connection);
           // String sql ="CREATE TABLE ACCOUNT(id int , username varchar(255), password varchar(255)); ";
            String sql ="INSERT INTO  ACCOUNT VALUES(1 , 'test', 'pass')";
            try(PreparedStatement statement = connection.prepareStatement(sql)){
                statement.execute();
             
            }
        }
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4.ORM: Object-Relation Mapping

 

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13746&tab=curriculum&category=questionDetail

 

 

JDBC 사용

    try(Connection connection = DriverManager.getConnection(url, username, password)) {
            System.out.println("Connection created: " + connection);
            String sql = "INSERT INTO ACCOUNT VALUES(1, 'keesun', 'pass');";
            try(PreparedStatement statement = connection.prepareStatement(sql)) {
                statement.execute();
            }
        }

 

도메인 모델 사용

Account account = new Account(“keesun”, “pass”);
accountRepository.save(account);

 

JDBC 대신 도메인 모델 사용하려는 이유?

  • 객체 지향 프로그래밍의 장점을 활용하기 좋으니까.

  • 각종 디자인 패턴

  • 코드 재사용

  • 비즈니스 로직 구현 및 테스트 편함.

 

 

 

ORM은 애플리케이션의 클래스와 SQL 데이터베이스의 테이블 사이의 맵핑 정보를 기술한 메타데이터를 사용하여,

자바 애플리케이션의 객체를 SQL 데이터베이스의 테이블에 자동으로 (또 깨끗하게) 영속화 해주는 기술입니다.

 

 

장점 :  생산성 , 유지보수성 ,성능 ,밴더 독립성

 

단점 :   학습비용

 

 

 

 

 

 

 

 

 

 

5.ORM 패러다임 불일치

 

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13747&tab=curriculum&category=questionDetail

 

 

 

 

 

 

 

 

 

 

 

6.ORM 패러다임 불일치

 

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13748&tab=curriculum&category=questionDetail

 

 

참조 :

https://velog.io/@jwpark06/SpringBoot에-JDBC로-Postgresql-연동하기

 

 

데이터베이스 실행

  • PostgreSQL 도커 컨테이너 재사용

  • docker start postgres_boot

 

스프링 부트

  • 스프링 부트 v2.*

  • 스프링 프레임워크 v5.*

 

스프링 부트 스타터 JPA

  • JPA 프로그래밍에 필요한 의존성 추가

    • JPA v2.*

    • Hibernate v5.*

  • 자동 설정: HibernateJpaAutoConfiguration

    • 컨테이너가 관리하는 EntityManager (프록시) 빈 설정

    • PlatformTransactionManager 빈 설정

 

JDBC 설정

  • jdbc:postgresql://localhost:5432/springdata

  • keesun

  • pass

 

application.properties

  • spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

  • spring.jpa.hibernate.ddl-auto=create

 

 

 

================================================= ================================================= ================================================= 

================================================= ================================================= ================================================= 

================================================= ================================================= ================================================= 

 

 

스프링부트 3.0.5         설정 파일  :  jPA    +    dev 툴 +      postsql +      lombok

 

설정 파일 다운로드

https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.0.5&packaging=jar&jvmVersion=17&groupId=com.jpa&artifactId=springdatajpa&name=springdatajpa&description=Demo%20project%20for%20Spring%20Boot&packageName=com.jpa.spring&dependencies=devtools,postgresql,lombok,data-jpa

 

 

 

=> 롬복 적용

 

=> 인텔리제이 스프링부트 자동빌드 적용

 

 

콘솔 색깔 설정

application.properties

spring.output.ansi.enabled=always

 

 

Account

package com.jpa.spring;


import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.Data;
import org.springframework.boot.autoconfigure.domain.EntityScan;

@Entity
@Data
public class Account {

    @Id
    @GeneratedValue
    private Long id;

    private String username;

    private String password;


}

 

 

JpaRunner

package com.jpa.spring;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.hibernate.Session;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@Transactional
public class JpaRunner implements ApplicationRunner {

    @PersistenceContext
    EntityManager entityManager;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Account account=new Account();
        account.setUsername("HongGilDong");
        account.setPassword("jpa");
        //entityManager.persist(account);

        Session session =entityManager.unwrap(Session.class);
        session.save(account);
    }


}

 

 

spring.datasource.platform=postgres  를 추가하면  spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true 제거해도 된다.

 

 

 

쿼리 파라미터 로그 남기기 설정하기

 

참조 : https://macaronics.net/index.php/m01/spring/view/2055


로그에 다음을 추가하기: SQL 실행 파라미터를 로그로 남긴다.
주의! 스프링 부트 3.x를 사용한다면 영상 내용과 다르기 때문에 다음 내용을 참고하자.


1)스프링 부트 2.x, hibernate5
org.hibernate.type: trace



외부 라이브러리 사용
https://github.com/gavlyukovskiy/spring-boot-data-source-decorator


스프링 부트를 사용하면 이 라이브러리만 추가하면 된다.
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'
> 참고: 쿼리 파라미터를 로그로 남기는 외부 라이브러리는 시스템 자원을 사용하므로, 개발 단계에서는
편하게 사용해도 된다. 하지만 운영시스템에 적용하려면 꼭 성능테스트를 하고 사용하는 것이 좋다.

 


2) 쿼리 파라미터 로그 남기기 - 스프링 부트 3.0

스프링 부트 3.x, hibernate6
org.hibernate.orm.jdbc.bind: trace


p6spy-spring-boot-starter 라이브러리는 현재 스프링 부트 3.0을 정상 지원하지 않는다.
스프링 부트 3.0에서 사용하려면 다음과 같은 추가 설정이 필요하다

 

 

1. org.springframework.boot.autoconfigure.AutoConfiguration.imports 파일 추가

src/resources/META-INF/spring/
org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.github.gavlyukovskiy.boot.jdbc.decorator.DataSourceDecoratorAutoConfiguration

 

폴더명: src/resources/META-INF/spring

파일명: org.springframework.boot.autoconfigure.AutoConfiguration.imports

 

 

2. spy.properties 파일 추가

src/resources/spy.properties
appender=com.p6spy.engine.spy.appender.Slf4JLogger

 

spy.properties 에 입력하지 말것

#appender=com.p6spy.engine.spy.appender.Slf4JLogger

 

이렇게 2개의 파일을 추가하면 정상 동작한다

 

 

 

application.properties 추가 설정

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

 

 

 

메인븐  라이브러리

		<dependency>
			<groupId>com.github.gavlyukovskiy</groupId>
			<artifactId>p6spy-spring-boot-starter</artifactId>
			<version>1.9.0</version>
		</dependency>

 

 

 

 

 

 

 

 

 

7.JPA 프로그래밍: 엔티티 맵핑

 

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13749&tab=curriculum&category=questionDetail

 

 

@Entity
“엔티티”는 객체 세상에서 부르는 이름.
보통 클래스와 같은 이름을 사용하기 때문에 값을 변경하지 않음.
엔티티의 이름은 JQL에서 쓰임.

 

@Table
“릴레이션" 세상에서 부르는 이름.


@Entity의 이름이 기본값.
테이블의 이름은 SQL에서 쓰임.

 

 

@Id
엔티티의 주키를 맵핑할 때 사용.
자바의 모든 primitive 타입과 그 랩퍼 타입을 사용할 수 있음
Date랑 BigDecimal, BigInteger도 사용 가능.
복합키를 만드는 맵핑하는 방법도 있지만 그건 논외로..

 

@GeneratedValue
주키의 생성 방법을 맵핑하는 애노테이션
생성 전략과 생성기를 설정할 수 있다.
기본 전략은 AUTO: 사용하는 DB에 따라 적절한 전략 선택
TABLE, SEQUENCE, IDENTITY 중 하나.

 

@Column
unique
nullable
length
columnDefinition

...

 

 

@Temporal
현재 JPA 2.1까지는 Date와 Calendar만 지원.

 

@Transient
컬럼으로 맵핑하고 싶지 않은 멤버 변수에 사용.
 

application.properties
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

 

Account

package com.jpa.spring;


import jakarta.persistence.*;
import jdk.jfr.Timestamp;
import lombok.Data;

import java.time.LocalDateTime;
import java.util.Date;

@Entity
@Data
public class Account {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    private String password;


    @Temporal(TemporalType.TIMESTAMP)
    private Date created=new Date();

    @Transient
    private String yes;

    private String no;


}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

8.JPA 프로그래밍: Value 타입 맵핑 (값 타입 매핑)

 

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13750&tab=curriculum&category=questionDetail

 

엔티티 타입과 Value 타입 구분  식별자가 있어야 하는가.  독립적으로 존재해야 하는가.

 

Value 타입 종류   기본 타입 (String, Date, Boolean, ...)
 Composite Value 타입
  Collection Value 타입
기본 타입의 콜렉션
컴포짓 타입의 콜렉션

 

Composite Value 타입 맵핑
@Embeddable
@Embedded
@AttributeOverrides
@AttributeOverride
 

 

Address 

package com.jpa.spring;

import jakarta.persistence.Embeddable;

@Embeddable
public class Address {

    private String street;
    private String city;
    private String state;
    private String zipCode;
}

 

 

Account

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="street",
                column = @Column(name="home_street")
            )
    })
    private Address address;


 

 

 

 

 

 

 

 

 

 

 

 

 

9.JPA 프로그래밍 4. 관계 맵핑

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13751&tab=curriculum&category=questionDetail

 

 

관계에는 항상 두 엔티티가 존재 합니다. 

둘 중 하나는 그 관계의 주인(owning)이고 다른 쪽은 종속된(non-owning) 쪽입니다.


해당 관계의 반대쪽 레퍼런스를 가지고 있는 쪽이 주인.

단방향에서의 관계의 주인은 명확합니다.  관계를 정의한 쪽이 그 관계의 주인입니다.

 

단방향 @ManyToOne
기본값은 FK 생성

 

단방향 @OneToMany
기본값은 조인 테이블 생성

 

양방향
FK 가지고 있는 쪽이 오너 따라서 기본값은 @ManyToOne 가지고 있는 쪽이 주인.
주인이 아닌쪽(@OneToMany쪽)에서 mappedBy 사용해서 관계를 맺고 있는 필드를 설정해야 합니다.

 

양방향
@ManyToOne (이쪽이 주인)


@OneToMany(mappedBy)
주인한테 관계를 설정해야 DB에 반영이 됩니다.
 

 

Account

package com.jpa.spring;


import jakarta.persistence.*;
import lombok.Data;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

@Entity
@Data
public class Account {
    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    private String password;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created=new Date();

    @Transient
    private String yes;

    private String no;


    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name="street",
                column = @Column(name="home_street")
            )
    })
    private Address address;


    //CascadeType.ALL 는 order
    //    persist(ownerA);
    //    persist(ownerB);
    //    persist(ownerB);
    //    persist(ownerB);
    //    persist(study);
    // =>persist를 각각 해줘야 하는데 CascadeType.ALL  적용하면  persist(study); 한번에 적용된다.
     @OneToMany(mappedBy ="owner", cascade = CascadeType.ALL)
    private Set<Study> studies=new HashSet<>();


    public void addStudy(Study study){
        this.getStudies().add(study);
        study.setOwner(this);
    }


    public void removeStudy(Study study){
        this.getStudies().remove(study);
        study.setOwner(null);
    }



}

 

Study

package com.jpa.spring;


import jakarta.persistence.*;
import lombok.Data;
import lombok.Getter;

@Entity
@Data
public class Study {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    private Account owner;


}

 

 

 

 

 

 

 

 

 

 

 

10. JPA 프로그래밍: Cascade

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13752&tab=curriculum&category=questionDetail

 

영속성전이(CASCADE)란 ?

부모 엔티티가 영속화될 때 자식 엔티티도 같이 영속화되고, 부모 엔티티가 삭제될 때 자식 엔티티도 삭제되는 등 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 전이되는 것을 의미합니다.

 

각각의 operations에 대한 설명은 다음과 같습니다.

  • CascadeType.ALL: 모든 Cascade를 적용
  •  
  • CascadeType.PERSIST: 엔티티를 영속화할 때, 연관된 엔티티도 함께 유지
  •  
  • CascadeType.MERGE: 엔티티 상태를 병합(Merge)할 때, 연관된 엔티티도 모두 병합
  •  
  • CascadeType.REMOVE: 엔티티를 제거할 때, 연관된 엔티티도 모두 제거
  •  
  • CascadeType.DETACH: 부모 엔티티를 detach() 수행하면, 연관 엔티티도 detach()상태가 되어 변경 사항 반영 X
  •  
  • CascadeType.REFRESH: 상위 엔티티를 새로고침(Refresh)할 때, 연관된 엔티티도 모두 새로고침

 

 

 

엔티티의 상태 변화를 전파 시키는 옵션.

 

잠깐? 엔티티의 상태가 뭐지?


Transient: JPA가 모르는 상태


Persistent: JPA가 관리중인 상태 (1차 캐시, Dirty Checking, Write Behind, ...)


Detached: JPA가 더이상 관리하지 않는 상태.


Removed: JPA가 관리하긴 하지만 삭제하기로 한 상태.
 

 

 

 

 

Post

package com.jpa.spring;

import jakarta.persistence.*;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Entity
@Data
public class Post {

    @Id
    @GeneratedValue
    @Column(name="post_id")
    private Long id;

    private String title;

    //CascadeType.ALL 는 comment
    //    persist(commentA);
    //    persist(commentB);
    //    persist(commentB);
    //    persist(commentB);
    //    persist(post);
    // =>persist를 각각 해줘야 하는데 CascadeType.ALL  적용하면  persist(study); 한번에 적용된다.
    @OneToMany(mappedBy = "post",  cascade = CascadeType.ALL)
    private List<Comment> comments =new ArrayList<>();

    /** Set 으로 할경우  hashCode 에 대한 StackOverflowError 나와서 id 에 대한 hashCode 를 설정해 줘야 한다.
    // StackOverflowError hashCode
     **/
    public void addComment(Comment comment){
        this.getComments().add(comment);
        comment.setPost(this);
    }


}

 

 

Comment

package com.jpa.spring;


import jakarta.persistence.*;
import lombok.Data;

@Entity
@Data
public class Comment {

    @Id
    @GeneratedValue
    @Column(name="comment_id")
    private Long id;

    private String comment;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="post_id")
    private Post post;

    
}

 

 

PostDTO

package com.jpa.spring;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@RequiredArgsConstructor
@ToString
public class PostDTO {

    private Long id;

    private String title;

    private Long commentId;
    private String comment;


    
}

 

CascadeType.ALL: 모든 Cascade를 설정으로 연속해서 데이터 등록및 삭제 처리가 가능하다.

 

만약에 설정을 하지 않는다면, 다음과 같은 코드를 추가해 줘야 한다.

entityManager.persist(comment1);

entityManager.persist(comment2);

entityManager.persist(comment3)

 

 

JpaRunner

package com.jpa.spring;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Component
@Transactional
public class JpaRunner implements ApplicationRunner {

    @PersistenceContext
    EntityManager entityManager;


//    public void run2(ApplicationArguments args) throws Exception {
//        Account account=new Account();
//        account.setUsername("HongGilDong");
//        account.setPassword("jpa");
//
//        //entityManager.persist(account);
//        Study study =new Study();
//        study.setName("Spring Data JPA");
//
//        //보조적인 설정
////        account.getStudies().add(study);
////        //항상 관계의 주인에 넣어줘야 한다.
////        study.setOwner(account);
//
//        //====>
//        account.addStudy(study);
//
//        Session session =entityManager.unwrap(Session.class);
//        session.save(account);
//        session.save(study);
//
//        Account kessun = session.load(Account.class, account.getId());
//        System.out.println(" ====================================" );
//        System.out.println("1.kessun = " + kessun.getUsername());
//
//        //더티 체킹
//        kessun.setUsername("whiteship");
//        kessun.setUsername("whiteship");
//        System.out.println(" ====================================" );
//        System.out.println("2.kessun = " + kessun.getUsername());
//    }



     @Override
     public void run(ApplicationArguments args) throws  Exception{
         Post post=new Post();
         post.setTitle("Spring Data JPA 언제 보나...");

        Comment comment =new Comment();
        comment.setComment("빨리 보고 싶어요.");
        post.addComment(comment);

        Comment comment1 =new Comment();
        comment1.setComment("곧 보여드릴께요");
        post.addComment(comment1);


//        Session session =entityManager.unwrap(Session.class);
//        session.save(post);

        entityManager.persist(post);

        /** cascade = CascadeType.ALL 설정 되어 있기 때문에 다음 코드를 넣지 않아도
         *  comment data 가 들어간다.
         * * **/
//        entityManager.persist(comment);
//        entityManager.persist(comment1); Post

         entityManager.flush();
         entityManager.close();
         List<PostDTO> resultList = entityManager.createQuery("select new com.jpa.spring.PostDTO( p.id, p.title, c.id, c.comment )  from  Post p  join  p.comments c on p.id=1",
                 PostDTO.class).getResultList();


         for(PostDTO p :resultList){
                System.out.println("resultList   = " + p);
         }
         /**
          출력
          p.getComments() = PostDTO(id=1, title=Spring Data JPA 언제 보나..., commentId=1, comment=빨리 보고 싶어요.)
          p.getComments() = PostDTO(id=1, title=Spring Data JPA 언제 보나..., commentId=2, comment=곧 보여드릴께요)
          * 
          */

         //삭제
         Post singleResult = entityManager.createQuery("select p from Post p where p.id = 1l ", Post.class).getSingleResult();
         System.out.println("singleResult = " + singleResult.getTitle());
         entityManager.remove(singleResult);
         entityManager.flush();
         entityManager.clear();

         List<Comment> commentList = entityManager.createQuery("select c from Comment c where c.post.id = 1l ", Comment.class).getResultList();
         System.out.println("CommentList = " + commentList.size());

     }


}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

11. Fetch

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13753&tab=curriculum&category=questionDetail

 

연관 관계의 엔티티를 어떻게 가져올 것이냐... 지금 (Eager)? 나중에(Lazy)?

  • @OneToMany의 기본값은 Lazy

  • @ManyToOne의 기본값은 Eager

 

 

참조 :   =>

자바 ORM 표준 JPA 프로그래밍 - 10. 객체지향 쿼리 언어2 - 중급 문법 ★ 페치 조인(fetch join)

 

 

 

 

 

 

 

 

 

 

 

 

12. JPA 프로그래밍: Query

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13754&tab=curriculum&category=questionDetail

 

@Entity
@Data
@ToString(of = {"id", "title"})
public class Post {


~

 

 

JpaRunner

    @Override
    public void run(ApplicationArguments args) throws Exception{
        Post post = new Post();
        post.setTitle("Spring Data JPA 언제 보나...");

        Comment comment = new Comment();
        comment.setComment("빨리 보고 싶어요.");
        post.addComment(comment);

        Comment comment1 = new Comment();
        comment1.setComment("곧 보여드릴께요");
        post.addComment(comment1);

        entityManager.persist(post);

        List<Post> resultList = entityManager.createQuery("select p from Post p join p.comments ", Post.class).getResultList();
        System.out.println("=========================================================");
        resultList.forEach(System.out::println);
        System.out.println("=========================================================");
    }

 

 

 

 

JPQL (HQL)

 

 

Criteria

 

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Post> criteria = builder.createQuery(Post.class);
        Root<Post> root = criteria.from(Post.class);
        criteria.select(root);
        List<Post> posts = entityManager.createQuery(criteria).getResultList();

 

 

Native Query

 

 

List<Post> posts = entityManager
                .createNativeQuery("SELECT * FROM Post", Post.class)
                .getResultList();

 

 

 

 

 

 

 

 

 

 

 

13. 스프링 데이터 JPA 소개 및 원리

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13755&tab=curriculum&category=questionDetail

 

 

 

JpaRepository<Entity, Id> 인터페이스

  • 매직 인터페이스

  • @Repository가 없어도 빈으로 등록해 줌.

 

@EnableJpaRepositories

  • 매직의 시작은 여기서 부터

 

매직은 어떻게 이뤄지나?

  • 시작은 @Import(JpaRepositoriesRegistrar.class)

핵심은 ImportBeanDefinitionRegistrar 인터페이스

 

package com.jpa.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@Transactional
public class 스프링데이터JPA소개및원리13  implements ApplicationRunner {

	@Autowired
	PostRepository postRepository;
	@Override
	public void run(ApplicationArguments args) throws Exception {
		System.out.println("=================================================");
		postRepository.findAll().forEach(System.out::println);
		System.out.println("=================================================");
	}
	
}

 

 

 

 

 

 

 

 

 

 

14. 핵심 개념 마무리

 

강의 :

https://www.inflearn.com/course/lecture?courseSlug=스프링-데이터-jpa&unitId=13756&tab=curriculum&category=questionDetail

 

    @Autowired
    PostRepository postRepository;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        Post post =new Post();
        post.setTitle("spring");

        Comment comment =new Comment();
        comment.setComment("hello");

        postRepository.save(post);
    }

 

 

데이터베이스와 자바

패러다임 불일치

ORM이란?

JPA 사용법 (엔티티, 벨류 타입, 관계 맵핑)

JPA 특징 (엔티티 상태 변화, Cascade, Fetch, 1차 캐시, ...)

주의할 점

  • 반드시 발생하는 SQL을 확인할 것.

  • 팁: “?”에 들어있는 값 출력하기

    • logging.level.org.hibernate.SQL=debug

    • logging.level.org.hibernate.type.descriptor.sql=trace

 

 

로그 설정

=>

https://macaronics.net/index.php/m01/spring/view/2088

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

인간은 태어났을 때는 자유스러웠으나 사회 속에서는 무수한 쇠사슬에 얽혀져 있다. -루소

댓글 ( 4)

댓글 남기기

작성