본문 바로가기

항해99/시험 리뷰

[항해99] Spring 주특기2 시험 리뷰

시험문제

1. 회원 테이블이 완성되어 있지 않습니다.
.http 파일의 Q1. 회원가입 API에 따라 테이블을 작성해 주세요.
entity 패키지의 member 클래스를 완성해 주세요.
예상 return값 (4번문제 풀기 전)
// A1. Response

[
  {
    "id": 1,
    "email": "sparta@sparta.com",
    "password": "4321",
    "address": "부산시",
    "phoneNumber": "01012341234",
    "nickname": "스파르타",
    "bookStore": null
  },
  {
    "id": 2,
    "email": "hanghae99@sparta.com",
    "password": "1234",
    "address": "서울시",
    "phoneNumber": "01012345678",
    "nickname": "르탄이",
    "bookStore": null
  }
]​

2. 서점에 등록된 책의 가격과 재고를 수정해야 합니다.
.http 파일의 Q2. *서점에 책 등록된 책 수량 수정 API*를 완성해 주세요.
service 패키지, TestService의 updateBook 메서드를 완성해 주세요.
예상 return값
.http를 확인해 주세요.
// A2. Response

[
  {
    "id": 1,
    "title": "자바의 정석 3판",
    "author": "남궁성",
    "price": 10000,
    "stock": 100,
    "bookStore": {
      "name": "스파르타 서울"
    }
  }
]​

3. “자바의정석”책을 서울점에서 부산점으로 옮기려고 합니다.
현재 만들어진 *Q3. 부산점에 자바의 정석 책 등록 API*로는 어째서인지 정보가 수정되지 않습니다.
올바르게 작동하도록 수정해 주세요.
service 패키지, TestService의 transferBook 메서드를 완성해 주세요.
예상 return값
// A3. Response

[
  {
    "id": 1,
    "title": "자바의 정석 3판",
    "author": "남궁성",
    "price": 10000,
    "stock": 100,
    "bookStore": {
      "name": "스파르타 부산"
    }
  },
  {
    "id": 2,
    "title": "자바 ORM 표준 JPA 프로그래밍",
    "author": "김영한",
    "price": 20000,
    "stock": 4,
    "bookStore": {
      "name": "스파르타 부산"
    }
  }
]​

4. 회원 테이블과 책 테이블간 다대다 매핑이 되어 있습니다.
Purchase 테이블을 중간 테이블로 설정하여 1:N, M:1 의 관계로 바꿔 주세요.
entity 패키지의 purchase 클래스, 연관된 클래스들을 수정해 주세요.
[http://localhost:8080/h2-console](<http://localhost:8080/h2-console>) 를 확인해 주세요.

5. 회원 테이블에 서점 테이블 FK 컬럼명을 Sparta_Store_Id로 바꿔주세요.
단, Member 클래스와 BookStore 클래스를 변경시키지 않아야 합니다.
entity 패키지의 member클래스를 완성해 주세요.
예상 return값
[http://localhost:8080/h2-console](<http://localhost:8080/h2-console>) 를 확인해 주세요.

서술형 문제

6. JPA에서, 기존의 정보를 수정하는 기능 작성 시 save 메서드가 필요 없는 이유와 동작 원리에 대해 서술해 주세요.

 

제출한 답안

Q1. Member 클래스 코드를 제출해 주세요.

package com.example.jpa_relation_test.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String email;
    private String password;
    private String address;
    private String phoneNumber;
    private String nickname;

    @ManyToOne
    @JoinColumn(name = "book_store_id")
    private BookStore bookStore;

    @ManyToMany
    private List<Book> books = new ArrayList<>();

    public Member(String email, String password, String address, String phoneNumber, String nickname) {
        this.email = email;
        this.password = password;
        this.address = address;
        this.phoneNumber = phoneNumber;
        this.nickname = nickname;
    }

}

 

Q2. updateBook 메서드 코드, BookRepository, Book 클래스를 제출해 주세요.

    // updateBook 메서드 코드
    
    @Transactional
    public void updateBook(Book book, Long bookStoreId, Long bookId) {
        Optional<Book> optionalBook = bookRepository.findById(bookId);
        
        if (optionalBook.isPresent()) {
            Book existingBook = optionalBook.get();
            
            existingBook.updateTitle(book.getTitle());
            existingBook.updateAuthor(book.getAuthor());
            existingBook.updatePrice(book.getPrice());
            existingBook.updateStock(book.getStock());
            
            if (bookStoreId != null) {
                Optional<BookStore> optionalBookStore = bookStoreRepository.findById(bookStoreId);
                if (optionalBookStore.isPresent()) {
                    BookStore bookStore = optionalBookStore.get();
                    existingBook.updateBookStore(bookStore);
                } else {
                    throw new RuntimeException("해당 ID에 해당하는 서점을 찾을 수 없습니다.: " + bookStoreId);
                }
            }
            
            bookRepository.save(existingBook);
        } else {
            System.out.println(bookId + "에 해당하는 책을 찾을 수 없습니다.");
        }
    }
// BookRepository

public interface BookRepository extends JpaRepository<Book, Long> {
    List<Book> findByBookStoreId(Long bookStoreId);
}
// Book 클래스

package com.example.jpa_relation_test.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String author;

    @Column(nullable = false)
    private Integer price;

    private Integer stock;

    @ManyToOne
    @JoinColumn(name = "bookstore_id")
    private BookStore bookStore;

    @ManyToMany
    @JoinTable(
            name = "member_book",
            joinColumns = @JoinColumn(name = "book_id"),
            inverseJoinColumns = @JoinColumn(name = "member_id")
    )
    private List<Member> members = new ArrayList<>();

    public Book(String title, String author, Integer price, Integer stock) {
        this.title = title;
        this.author = author;
        this.price = price;
        this.stock = stock;
    }


    public void updateTitle(String title) {
        this.title = title;
    }

    public void updateAuthor(String author) {
        this.author = author;
    }

    public void updatePrice(Integer newPrice) {
        this.price = newPrice;
    }

    public void updateStock(Integer newStock) {
        this.stock = newStock;
    }


    public void updateBookStore(BookStore bookStore) {
        this.bookStore = bookStore;
    }
}

 

Q3. transferBook 메서드 코드, Book 클래스 코드를 제출해 주세요.

// transferBook 메서드 코드

public void transferBook(Long bookId, Long bookStoreId) {
        Book book = bookRepository.findById(bookId)
                .orElseThrow(() -> new RuntimeException("해당 아이디의 책을 찾을 수 없습니다. : " + bookId));

        BookStore bookStore = bookStoreRepository.findById(bookStoreId)
                .orElseThrow(() -> new RuntimeException("해당 아이디의 서점을 찾을 수 없습니다.: " + bookStoreId));

        book.updateBookStore(bookStore);
        bookRepository.save(book);
        bookStore.addBook(book);
    }
}
// Book 클래스 코드

package com.example.jpa_relation_test.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String author;

    @Column(nullable = false)
    private Integer price;

    private Integer stock;

    @ManyToOne
    private BookStore bookStore;

    @ManyToMany
    @JoinTable(
            name = "member_book",
            joinColumns = @JoinColumn(name = "book_id"),
            inverseJoinColumns = @JoinColumn(name = "member_id")
    )
    private List<Member> members = new ArrayList<>();

    public Book(String title, String author, Integer price, Integer stock) {
        this.title = title;
        this.author = author;
        this.price = price;
        this.stock = stock;
    }


    public void updateTitle(String title) {
        this.title = title;
    }

    public void updateAuthor(String author) {
        this.author = author;
    }

    public void updatePrice(Integer newPrice) {
        this.price = newPrice;
    }

    public void updateStock(Integer newStock) {
        this.stock = newStock;
    }


    public void updateBookStore(BookStore bookStore) {
        this.bookStore = bookStore;
    }
}

 

Q4. Purchase, Book, Member 클래스 코드를 제출해 주세요.

// Purchase

package com.example.jpa_relation_test.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Getter
@NoArgsConstructor
public class Purchase {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private Member member;

    @ManyToOne
    private Book book;

    private int quantity;

    public Purchase(Member member, Book book, int quantity) {
        this.member = member;
        this.book = book;
        this.quantity = quantity;
    }
}
// Book 

package com.example.jpa_relation_test.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String author;

    @Column(nullable = false)
    private Integer price;

    private Integer stock;

    @ManyToOne
    @JoinColumn(name = "bookstore_id")
    private BookStore bookStore;

    @ManyToMany
    @JoinTable(
            name = "member_book",
            joinColumns = @JoinColumn(name = "book_id"),
            inverseJoinColumns = @JoinColumn(name = "member_id")
    )
    private List<Member> members = new ArrayList<>();

    public Book(String title, String author, Integer price, Integer stock) {
        this.title = title;
        this.author = author;
        this.price = price;
        this.stock = stock;
    }


    public void updateTitle(String title) {
        this.title = title;
    }

    public void updateAuthor(String author) {
        this.author = author;
    }

    public void updatePrice(Integer newPrice) {
        this.price = newPrice;
    }

    public void updateStock(Integer newStock) {
        this.stock = newStock;
    }


    public void updateBookStore(BookStore bookStore) {
        this.bookStore = bookStore;
    }

    public Long getId() {
        return id;
    }
}
// Member

package com.example.jpa_relation_test.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String email;
    private String password;
    private String address;
    private String phoneNumber;
    private String nickname;

    @ManyToOne
    @JoinColumn(name = "book_store_id")
    private BookStore bookStore;

    @ManyToMany(mappedBy = "members")
    private List<Book> books = new ArrayList<>();

    public Member(String email, String password, String address, String phoneNumber, String nickname) {
        this.email = email;
        this.password = password;
        this.address = address;
        this.phoneNumber = phoneNumber;
        this.nickname = nickname;
    }
}

 

Q5. Member 클래스 코드를 제출해 주세요.

package com.example.jpa_relation_test.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
@Table(name = "member")
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String email;
    private String password;
    private String address;
    private String phoneNumber;
    private String nickname;

    @ManyToOne
    @JoinColumn(name = "Sparta_Store_Id")
    private BookStore bookStore;

    @ManyToMany(mappedBy = "members")
    private List<Book> books = new ArrayList<>();

    public Member(String email, String password, String address, String phoneNumber, String nickname) {
        this.email = email;
        this.password = password;
        this.address = address;
        this.phoneNumber = phoneNumber;
        this.nickname = nickname;
    }
    public void addBook(Book book) {
        this.books.add(book);
        book.getMembers().add(this);
    }
    
    public void removeBook(Book book) {
        this.books.remove(book);
        book.getMembers().remove(this);
    }


}

 

Q6. JPA에서, 기존의 정보를 수정하는 기능 작성 시 save 메서드가 필요 없는 이유와 동작 원리에 대해 서술해 주세요.

JPA는 엔티티를 데이터베이스에 저장하거나 수정할 때 도와줍니다., 이때 엔티티를 수정해도 save 메서드를 호출할 필요가 없는 이유는 JPA가 엔티티의 상태 추적을 잘하고 있기 때문입니다. 이미 데이터베이스에서 정보를 가져와서 Java 객체로 변환했다고 가정해봅시다. 이 객체는 JPA의 영속성 컨텍스트에 의해 추적되고 있습니다. 이 상태에서 우리가 객체를 변경한다면, JPA는 이 변경 내용을 감지하고 있습니다. 변경 내용을 데이터베이스에 반영하려면 save 메서드를 호출하지 않고도 변경된 객체를 다시 영속성 컨텍스트에 넣어주면 됩니다. 그러면 JPA는 변경된 내용을 데이터베이스에 알아서 반영해 줄 수 있습니다. JPA는 객체를 수정할 때마다 이것을 추적하고,우리가 DB에 저장하거나 수정할 때 이것들을 처리해줍니다. 그래서 그냥 객체를 변경하고, JPA가 나머지를 처리하게 할 수 있습니다.

결과

 

급하게 구현하다보니까 코드가 좀 더럽게(?) 짠다는 느낌을 받았는데, 이렇게 보니까 진짜 체감이 확 된다...

감점된 부분은 구매 테이블 연결을 안했다...(바보같은 나...)

시간 될 때 코드 수정해서 다시 테스트 진행해봐야겠다.