스프링/스프링부트+JPA - 블로그

스프링부트+JPA 블로그 프로젝트 03 DB세팅, 모델링, 연관관계

H-V 2021. 8. 27. 21:15

유투버 '데어프로그래밍'님 강의 참조

 

 

1) 모델링 및 DB테이블 세팅

 

- User

  • MVC 패턴중 M의 해당하는 'Model'. 어플리케이션에 사용되는 정보들을 나타낸다. 이 모델 객체가 비지니스의 로직과 상태를 가지고 있다
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@DynamicInsert
@Entity
public class User {
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;//시퀀스,Auto_Increment 용, 사용자가 많을경우 Long
	
	@Column(nullable = false, length = 100, unique = true)
	private String username; //사용자가 쓰는 아이디
	
	@Column(nullable = false, length = 100)
	private String password;
	
	@Column(nullable = false, length = 50)
	private String email;
	
	@CreationTimestamp
	private Timestamp createDate;
	
	@ColumnDefault("'user'")
	private String role;
}
  • 클래스 생성 후 반드시 yml에서 'ddl-auto' 부분을 체크 하여 최초 테이블 생성시에는 'create'로 선언이 되어있는지 확인 해야한다
  • 나중에 작업을 이어나갈때는 반드시 'update'로 바꿔나야한다
  • 아이디가 중복이 되면 안된다. 반드시 unique를 걸어주자!
  • 서버를 시작시켜보면..

잘 만들어 진다!

 

 

- Board

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Board {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	
	@Column(nullable = false, length = 100)
	private String title;
	
	@Lob//대용량 데이터용 - 섬머노트를 위한
	private String content; 
	

	private int count;
	
	
	@ManyToOne // Many = Board, User = One
	@JoinColumn(name="userId")
	private User user;
	
	@CreationTimestamp
	private Timestamp createDate;
}
  • 여기서 ORM의 장점이 나온다. 자바는 오브젝트를 객체로 저장이 되지만 DB는 불가능 하다. 이것을 어노테이션을 통해 테이블명을 지정 해 줄 수 있고, User 오브젝트를 객체로 받았지만 ORM이 자동적으로 DB방식으로 바꿔서 저장을 하는 것. 즉 FK키 없이도 가능하다. (ORM 방식에서는 유저아이디값을 받아올때는 int userId로 하지 않는다)
  • FK 없이 연관관계를 설정하는것이 @ManyToOne -> 한명의 User는 여러개의 Board를 쓸 수 있다

 

 

 

 

- Reply

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Reply {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	
	@Column(nullable = false, length = 200)
	private String content;
	
	@CreationTimestamp
	private Timestamp createDate;
	
	@ManyToOne
	@JoinColumn(name="boardId")
	private Board board;
	
	@ManyToOne
	@JoinColumn(name="userId")
	private User user;
}
  • 연관관계의 중요성이 부각 된다. 또한 ManyToOne, OneToMany, OneToOne 은 정말 햇갈리게 한다!
  • Reply 클래스에서 @ManyToOne이면 여러개의 답글은 한 게시글에 달린다, 여러개의 답글은 한 유저가 쓸 수 있다

 

 

2) 연관 관계

  • 앞서 세가지의 테이블을 만들었는데 여기서 연관관계가 엮어있지만 끝난게 아니다. 그 이유는 연관관계의 주인을 설정해야한다
  • 연관관계의 주인은 FK키를 누가 가졌느냐에 따라 정해 진다
  • 예로 게시판 상세보기시에 나오는 정보는 앞서 만든테이블 모두를 거치게 된다. 스프링부트+JPA 방식이 아니었다면 세개 모드를 SELECT하여 조인하는 방식을 했겠지만 지금의 방식으로는 BOARD만 셀렉트하여 진행 가능 하다
  • JPA+ORM이 모델링 되어있는 클래스를 보고 자동적으로 불러야할 또는 걸러야할 데이터를 DB에서 받기 때문이다. (쿼리문으로 SLELCT*FROM BOARD WHERE ID = 1로 날려도 JPA에서는 BOARD클래스에서 USER오브젝트를 보고 거기에 맞춰서 프로세스한다!)

 

  • 그렇다면 현재 세개의 테이블을 사용을 하였고 게시판 상세보기를 클릭하게되면 모든 테이블을 거쳐서 나와야하는게 정상이다 즉, BOARD 클래스에 Reply 오브젝트 객체도 추가해야한다
  • 하지만 답글같은 경우 JoinColum을 안해도 된다 왜냐 replyId값은 한 테이블의 한열에 여러개를 줄 수 없기 때문이다. (DB의 1정규화 -> 원자성을 가진다 를 반드시 유지해야 한다)

    ID TITLE CONTENT USERID REPLYID CREATEDATE
    1 안녕 반가워 1 여러개가 달릴 경우 아이디를 1,2,3,4,5 이렇게 줄 수 없다는 말! 2021.08.27


  • 즉 게시물 상세보기를 예로들면 상세보기시에 답글은 누가, 몇개나 달렸는지만 보이면 되는 것. Board를 셀렉트할때 키없이 DB의 내용만 던져줘 라고 요청해야한다. 
    public class Board {
        ...
            @OneToMany(mappedBy="board")
            private List<Reply> replies;​
  • 게시글은 여러개가 달리기때문에 List로 객체화 시켰고 @OneToMany로 하나의 게시글에 여러개의 답글이 달린다
  • 또한 mappedBy라는 기능을 통해 Reply클래스의 Board board 객체를 받아오고 값만 들고 오게 된다
  • 쉽게 풀이하면 mappedBy="객체" 는 연관관계의 주인이 아니다(FK가 아님을 뜻함) 즉 DB에 칼럼을 만들지 마세요 가 된다 
  • 위에서 언급한대로 연관관계의 주인들은 유저의 id와 보드의 id가 되는 것!
  • 또한 UI에 따라 Fetch 전략을 이해하여야한다
public class Board {
...
	@ManyToOne(fetch = FetchType.EAGER) // Many = Board, User = One
	@JoinColumn(name="userId")
	private User user;
	
	@OneToMany(mappedBy="board", fetch = FetchType.EAGER)
	private List<Reply> replies;
  • 반드시 필요한 테이블내용이면 EAGER, 필요할때만 가져오는 내용이면 LAZY(예:댓글 펼치보기는 상세보기시에 무조건 안나와도 되는 데이터)로 제약을 걸 수 있다.