인턴을 했을 때 JPA 를 쓰긴 썼었는데 안 쓴거나 마찬가지였던 것 같다ㅠㅠㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

이전에는 아래와 같이 객체를 테이블에 맞춰서 모델링 했었음...

class Job{
    @Id
    private String jobId
    ...
}
class Step{
    @Id
    private String stepId;
    private String jobId;
    ...
}

이렇게 했을 때는 객체를 테이블에 저장하거나 조회할 때는 쉽고 편하다.

하지만 job에서 step을 조회할때, 또는 step에서 job을 조회하는 경우 참조된 객체를 가져올 수 없다.

물론 이 때는 데이터베이스에 저장이 주 기능이어서 딱히 상관없었을 수도 있다,,,

 

이번 토이 프로젝트에서는 JPA를 이용하여 객체지향 모델링을 해 볼건데

이번에는 객체 참조를 통해 관계를 맺도록 해볼것이다.

 

  • build.gradle dependency 추가

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

 

server:
  address: localhost
  port: 8080

spring:
  jpa:
    show-sql: true # API 호출시, SQL 문을 콘솔에 출력
    generate-ddl: true # DDL 정의시 데이터베이스의 고유 기능을 사용 ex) 테이블 생성, 삭제 등
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
  datasource:
    url: jdbc:mysql://localhost:3306/ewhaianDB?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 
    driver-class-name: com.mysql.cj.jdbc.Driver

 

  • Entity class 생성,,,을 하기 전에 저번에 정의했던 연관관계를 다시 보면 (객체는 참조가 있는 방향으로만 조회가 가능하다.)

    • 회원-글/시간표/강평/댓글: 일대 다 관계

    • 글-댓글: 일대 다 관계

    • 글/댓글-사진: 일대 다 관계

    • 강의-강의평가: 일대 다 관계

    • 시간표-강의:다대 다 관계

      • 시간표에 다른 강의 여러개 넣을 수 있고

      • 같은 강의가 여러 시간표에 들어갈 수 있다

      • --> 다대 다 관계는 관계형 데이터베이스 뿐만 아니라 엔티티에서도 거의 사용하지 않는다고 함

      • --> 따라서 연결 엔티티 강의시간표를 추가해서 일대다 관계+다대일 관계로 만들도록 한다.

      • 강의 시간표에는 담은 강의의 학점 합도 포함하도록 한다.

    • 추가) 즐겨찾기의 경우도 다대다 관계이므로 관계를 쪼개도록 한다.

 

 

 

 

 

 


  • JPA를 사용할 때 양방향 관계에서 주의할 점

@Entity
@Getter @Setter
public class BookStore{
    @Id @GeneratedValue
    private Integer id;
    
    private String name;
    
    @OneToMany(mappedBy="bookStore")
    private Set<Book> books=new HashSet<>();
    
    void add(Book book){
        //book.setBookStore(this); 이 부분을 꼭 설정해주도록
        this.books.add(book);
    }
}
@Entity
@Getter @Setter
public class Book{
    @Id @GeneratedValue
    private Integer id;
    private Sring isbn;
    private String title;
    
    @ManyToOne
    private BookStore bookStore;
}

위와 같이 객체를 정의해두고 테스트 코드를 아래와 같이 돌렸을 때 결과를 확인하면

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoJpaTestApplicationTests{
    @Autowired
    BookStoreRepository bookStoreRepository
    
    @Autowired
    BookRepository bookRepository
    
    @Test
    public void contextLoads(){
        BookStore bookStore=new BookStore();
        bookStore.setName("시애틀 책방");
        bookStoreRepository.save(bookStore);
        
        Book book=new Book();
        book.setTitle("JPA 공부 좀 하면서 쓰세요.");
        bookStore.add(book);
        bookRepository.save(book);
    }
}

--> book DB를 확인하면 bookStore id가 없다. (연관 관계 맵핑이 안되어 있다.)

 

mappedBy가 없을 때에는 Book과 BookStore은 양방향 관계가 아니고 서로 다른 단방향 관계 2개이다.

BookStore에서 Book을 참조하는 OneToMany 관계는 기본적으로 join 테이블(book_store_id - book_id)이 생성된다.

 

여기서 mappedBy="BookStore"를 써주면 양방향 관계가 된다. (OneToMany와 ManyToOne을 하나로 묶어준다.)

--> 이 때 관계의 주인을 Book(Many에 해당하는 쪽)으로 설정한다.

이 경우에는 join테이블이 생기는 것이 아니라 Book과 BookStore 테이블 2개만 생기고,

foreign key를 Book쪽에서 가지고 있게 된다. (Book 테이블에 book_store_id가 있음)

 

즉, mappedBy는 관계의 주인을 알려준다.

= 관계의 주인이 Book이고, Book에서 자기 자신을 BookStore라고 참조하고 있다는 뜻

= 이 경우 관계의 주인인 쪽에 관계가 설정 되어야 데이터베이스에 반영된다.

= add를 할 때 관계의 주인인 Book에 관계를 설정해야 sync가 된다.

 

출처

https://www.youtube.com/watch?v=brE0tYOV9jQ

https://victorydntmd.tistory.com/208

https://velog.io/@conatuseus/%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EB%A7%A4%ED%95%91-%EA%B8%B0%EC%B4%88-1-i3k0xuve9i

 

'Java (+ Spring)' 카테고리의 다른 글

Java Unit Test: Junit5  (0) 2021.02.10
Spring Boot: Spring Security & 카카오 로그인 API(...ing)  (0) 2020.10.06
Spring: Spring MVC 설정 하기  (0) 2020.07.26
Android: tutorial page  (0) 2020.07.18
Android: Launch screen  (0) 2020.07.16

+ Recent posts