ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [2주차]DB 설계(by JPA)
    SpringBoot 2023. 11. 12. 18:59

    2주차 과제 시 작 

     

    ERD

    게시판 하나에 여러 개의 댓글이 달릴 수 있기 때문에

    Board(게시판)과 Comment(댓글) DB를 1:N 관계로 설계했다

     

     

    Board DB

    테이블명 Board(게시판)
    속성 이름 데이터 타입
    글 제목 title VARCHAR(40)  
    작성 시간 write_time DATETIME  
    수정 시간 edit_time DATETIME  
    내용 content VARCHAR(10000)  
    글 번호 b_id BIGINT PK
    작성자 writer_b VARCHAR(20)  

    제목, 작성 시간, 수정 시간, 내용, 글ID, 글 작성자 정보를 저장하고, 글ID를 식별자로 사용했다. 

     

    Comment DB 

    테이블명 Comment(댓글)
    속성 이름 데이터 타입
    댓글 번호 BIGINT PK
    글 번호 BIGINT FK - Board.글 번호
    작성 시간 DATETIME  
    수정 시간 DATETIME  
    댓글 내용 VARCHAR(10000)  
    댓글 작성자 VARCHAR(20)  

    작성 시간, 수정 시간, 내용, 글ID(FK), 댓글ID, 댓글 작성자 정보를 저장하고, 댓글ID를 식별자로 사용했다. 

    글ID는 Board DB의 식별자를 외래키로 사용한다. 

     

     

    그러나!

    SQL문으로 DB를 생성하는 것이 아닌, JPA로 DB에 자동으로 SQL을 작성하는 것이 이번 과제의 목표이므로 

    아래에서 관련 내용을 다뤄보도록 할 것이다 

     

    그 전에 앞서 

    지난 주에 연결해 둔 DB가 잘 작동되는지 확인해 보았다 

     

     

     

     

    먼저 프로젝트 구조 

    엔티티/리포지토리/테스트 폴더를 구분해서 폴더링 함 

     

    application.properties 

    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/GDSC?serverTimezone=Asia/Seoul
    
    spring.datasource.username=root
    spring.datasource.password=0000
    
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
    spring.jpa.show-sql=true
    spring.jpa.hibernate.ddl-auto=create
    
    spring.jpa.properties.hibernate.dialect.storage_engine=innodb

     

    주로 SQL 관련 설정을 해주었다 

     

    build.gradle - dependencies 

    MySQL 및 lombok 등 관련 설정을 추가해줬다 

     

    엔티티 관련 코드(Board.java / Comment.java) 

    #Board.java 
    
    package gdsctuk.sbbasic.sptingbootstudybasic.model;
    
    import lombok.Builder;
    import lombok.Getter;
    
    import jakarta.persistence.*;
    import java.time.LocalDateTime;
    
    @Getter
    @Entity
    @Table(name = "Board")
    public class Board {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(nullable = false, updatable = false)
        private Long b_id;
    
        @Column(length = 40, nullable = false)
        private String title;
    
        @Column(length = 10000)
        private String content;
    
        @Column(length = 20)
        private String writer_b;
    
        private LocalDateTime write_time;
        private LocalDateTime edit_time;
    
        @PrePersist
        public void prePersist() {
            this.write_time = LocalDateTime.now();
            this.edit_time = this.write_time;
        }
    
        @PreUpdate
        public void preUpdate() {
            this.edit_time = LocalDateTime.now();
        }
    
        @Builder
        public Board(Long b_id, String title, String content, String writer_b, LocalDateTime write_time, LocalDateTime edit_time) {
            this.b_id = b_id;
            this.title = title;
            this.content = content;
            this.writer_b = writer_b;
            this.write_time = write_time;
            this.edit_time = edit_time;
        }
    
        // 기본 생성자
        public Board() {
        }
    }
    # Comment.java
    
    package gdsctuk.sbbasic.sptingbootstudybasic.model;
    
    import jakarta.persistence.*;
    import lombok.Builder;
    import lombok.Getter;
    
    import java.time.LocalDateTime;
    import java.util.Date;
    
    @Getter
    @Entity
    @Table(name = "Comment")
    public class Comment {
    
        @Id
        @GeneratedValue(strategy= GenerationType.IDENTITY)
        @Column(nullable = false, updatable = false)
        private Long c_id;
    
        @Column(nullable = false, updatable = false)
        private Long b_id;
    
        @Column(length = 20)
        private String writer_c;
    
        @Column(length = 10000)
        private String content;
    
    
        private LocalDateTime write_time;
        private LocalDateTime edit_time;
    
        @PrePersist
        public void prePersist() {
            this.write_time = LocalDateTime.now();
            this.edit_time = this.write_time;
        }
    
        @PreUpdate
        public void preUpdate() {
            this.edit_time = LocalDateTime.now();
        }
    
        @Builder
        public Comment(Long c_id, Long b_id, String writer_c, String content, LocalDateTime write_time, LocalDateTime edit_time) {
            this.c_id = c_id;
            this.b_id = b_id;
            this.writer_c = writer_c;
            this.content = content;
            this.write_time = write_time;
            this.edit_time = edit_time;
        }
    
        // 기본 생성자
        public Comment() {
        }
    }

    작성 시간 및 수정 시간에 대한 자동 설정은 다른 블로그 분의 코드를 참고하였다 

    (https://jforj.tistory.com/257)

     

     

    리포지토리 관련 코드(BoardRepository, CommentRepository)

     

     

    테스트 관련 코드 (BoardRepositoryTest, CommentRepositoryTest)

    package gdsctuk.sbbasic.sptingbootstudybasic.model;
    
    import gdsctuk.sbbasic.sptingbootstudybasic.repository.BoardRepository;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.List;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertNotNull;
    
    @SpringBootTest
    class BoardRepositoryTest {
    
        @Autowired
        private BoardRepository boardRepository;
    
        @Test
        @Transactional
        void saveBoard() {
            // Given
            Board board = Board.builder()
                    .title("Test Title")
                    .content("Test Content")
                    .writer_b("Test Writer")
                    .build();
    
            // When
            Board savedBoard = boardRepository.save(board);
    
            // Then
            assertNotNull(savedBoard.getB_id()); // 식별자가 생성되었는지 확인
            assertEquals("Test Title", savedBoard.getTitle());
            assertEquals("Test Content", savedBoard.getContent());
            assertEquals("Test Writer", savedBoard.getWriter_b());
            assertNotNull(savedBoard.getWrite_time());
            assertNotNull(savedBoard.getEdit_time());
        }
    
        @Test
        @Transactional
        void findAllBoards() {
            // Given
            Board board1 = Board.builder().title("Title 1").content("Content 1").writer_b("Writer 1").build();
            Board board2 = Board.builder().title("Title 2").content("Content 2").writer_b("Writer 2").build();
    
            boardRepository.save(board1);
            boardRepository.save(board2);
    
            // When
            List<Board> boards = boardRepository.findAll();
    
            // Then
            assertEquals(2, boards.size());
        }
    }
    package gdsctuk.sbbasic.sptingbootstudybasic.model;
    
    import gdsctuk.sbbasic.sptingbootstudybasic.model.Comment;
    import gdsctuk.sbbasic.sptingbootstudybasic.repository.CommentRepository;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.time.LocalDateTime;
    import java.util.List;
    
    import static gdsctuk.sbbasic.sptingbootstudybasic.model.Comment.*;
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertNotNull;
    
    @SpringBootTest
    class CommentRepositoryTest {
    
        @Autowired
        private CommentRepository commentRepository;
    
        @Test
        @Transactional
        void saveComment() {
            // Given
            Comment comment = Comment.builder()
                    .b_id(1L)
                    .writer_c("Test Writer")
                    .content("Test Content")
                    .build();
    
            // When
            Comment savedComment = commentRepository.save(comment);
    
            // Then
            assertNotNull(savedComment.getC_id()); // 식별자가 생성되었는지 확인
            assertEquals(1L, savedComment.getB_id());
            assertEquals("Test Writer", savedComment.getWriter_c());
            assertEquals("Test Content", savedComment.getContent());
            assertNotNull(savedComment.getWrite_time());
            assertNotNull(savedComment.getEdit_time());
        }
    
        @Test
        @Transactional
        void findCommentsByBId() {
            // Given
            Comment comment1 = Comment.builder().b_id(1L).writer_c("Writer 1").content("Content 1").build();
            Comment comment2 = Comment.builder().b_id(1L).writer_c("Writer 2").content("Content 2").build();
    
            commentRepository.save(comment1);
            commentRepository.save(comment2);
    
            // When
            List<Comment> comments = commentRepository.findAllByBId(1L);
    
            // Then
            assertEquals(2, comments.size());
        }
    }

    Test 코드는 특히 다른 분들 코드를 많이 참고했다... 

     

     

    BoardRepositoryTest에서 CommentRepositoryTest로 잘 넘어가는 걸 볼 수 있었고 

    test 또한 성공적으로 빌드됨을 볼 수 있다 

    그럼 이제 실제 MySQL에 DB가 생성되어 있는지 여부를 확인해 봐야 하는데 

     

     

     

    입력한 대로 테이블이 자동 구성되어 있다 

     

     

     

    MySQL에서 DataBase -> Reverse Engineering 을 통해서도 ERD를 그릴 수 있는데 

    관계는 따로 추가해 주었고, board id의 경우 comment DB에서 외래키로 참조하게 되는데 

    그 부분이 잘 표현되지 않은 것 같아서 추가로 그 부분을 수행해 봐야 할 것 같다 

    댓글