2022.09.07/DBMS

Jimin·2022년 9월 7일
0

비트캠프

목록 보기
38/60
post-thumbnail
  • board-app 프로젝트 수행
      1. DBMS 도입하기: DBMS를 이용해 데이터를 처리하는 방법

ServerApp을 DBMS로 교체하기

ServerApp: 데이터 관리(CRUD)
DBMS: DataBase Management System, 데이터관리시스템

DBMS 도입하기

board-app project
app-client

1단계 - 테이블을 정의한다.

  • 멤버 및 게시글 DB 모델링
    • mode.exerd
  • SQL DDL 작성
    • ddl.sql
  • DBMS에 테이블 생성

2단계 - 테스트용 예제 데이터를 입력한다.

  • 회원 데이터 및 게시글 데이터 입력
    • data.sql

3단계 - MariaDB용 JDBC Driver를 추가한다.

  • search.maven.org 사이트에서 mariadb-client
  • build.gradle 파일에 의존 라이브러리 정보 추가
  • gradle eclipse 실행
  • 이클립스 IDE에서 프로젝트 갱신
  • 프로젝트에 mariadb jdbc driver가 추가되었는지 확인

4단계 - MariaDB 서버와 연동하는 MemberDao를 정의한다.

  • com.bitcamp.board.domain.Board 클래스 변경

    • createdDate 필드를 Java.sql.Date 타입으로 변경
    • 기타 메서드 정리
  • com.bitcamp.board.dao.MariaDBMemberDao 클래스 정의

  • Board Domain class

public class Board{ 

  // 인스턴스를 생성할 때 준비되는 메모리를 선언
  public int no;
  public String title;
  public String content;
  public int memberNo;
  public String password;
  public int viewCount;
  public Date createdDate;

  @Override
  public String toString() {
    return "Board [no=" + no + ", title=" + title + ", content=" + content + ", memberNo="
        + memberNo + ", password=" + password + ", viewCount=" + viewCount + ", createdDate="
        + createdDate + "]";
  }
}
  • MariaDBMemberDao class
public class MariaDBMemberDao {

  public int insert(Member member)throws Exception {
    try(
        Connection con = DriverManager.getConnection( // 얘네가 네트워크 통신을 대신 처리해서 우리가 socket 처리를 일일히 할 필요가 없다.
            "jdbc:mariadb://localhost:3306/studydb", "study", "1111");
        PreparedStatement pstmt = con.prepareStatement(
            "insert into app_member(name, email, pwd) values(?, ?, sha2(?,  256))") // 값을 넣어야 할 자리를 ?로 표시한다. (in-parameter)
        ){
      pstmt.setString(1, member.name); // 인덱스는 1부터 시작한다.
      pstmt.setString(2, member.email);
      pstmt.setString(3, member.password);

      return pstmt.executeUpdate();
    }
  }

  public int update(Member member) throws Exception{
    try(
        Connection con = DriverManager.getConnection( 
            "jdbc:mariadb://localhost:3306/studydb", "study", "1111");
        PreparedStatement pstmt = con.prepareStatement(
            "update app_member set name = ?, email=?, pwd=sha2(?, 256) where mno = ?") /
        ){
      pstmt.setString(1, member.name);
      pstmt.setString(2, member.email);
      pstmt.setString(3, member.password);
      pstmt.setInt(4, member.no);

      return pstmt.executeUpdate();
    }
  }

  public Member findByNo(int no)  throws Exception{
    try(
        Connection con = DriverManager.getConnection( 
            "jdbc:mariadb://localhost:3306/studydb", "study", "1111");
        PreparedStatement pstmt = con.prepareStatement(
            "select mno, name, email, cdt from app_member where mno=" + no);
        // no 자체가 int 타입이라 이런식으로 가능,String은 공격 위험 있어서 불가.
        // pstmt.setInt(1, no); // 변수 선언만 try  () 안에 들어갈 수 있다.
        ResultSet rs = pstmt.executeQuery() // select 문
        ) // try()
    {
      if(!rs.next()) return null; // 결과가 존재하지 않는 경우, 일치하는 번호가 없는 것이다.
      Member member = new Member();
      member.no = rs.getInt("mno");
      member.name = rs.getString("name");
      member.email = rs.getString("email");
      member.createdDate = rs.getDate("cdt");
      return member;
    }// try() {}
  }


  public int delete(int no) throws Exception{
    try(
        Connection con = DriverManager.getConnection( 
            "jdbc:mariadb://localhost:3306/studydb", "study", "1111");
        PreparedStatement pstmt1 = con.prepareStatement( "delete from app_board where mno = ?"); // 자식 데이터 지우기
        PreparedStatement pstmt2 = con.prepareStatement( "delete from app_member where mno = ?") // 부모 데이터 지우기
        ) //try ()
    {
      // 자식 데이터 지우기 - 회원이 작성한 게시글 삭제
      pstmt1.setInt(1, no); 
      pstmt1.executeUpdate();
      // 부모 데이터 지우기 - 회원 데이터 삭제
      pstmt2.setInt(1, no); 
      return pstmt2.executeUpdate();
    } // try() {}
  }

  public List<Member> findAll() throws Exception{
    try(
        Connection con = DriverManager.getConnection( "jdbc:mariadb://localhost:3306/studydb", "study", "1111");
        PreparedStatement pstmt = con.prepareStatement( "select mno, name, email from app_member");
        ResultSet rs = pstmt.executeQuery()
        ) // try()
    {
      ArrayList<Member> list = new ArrayList<>();
      while(rs.next()) {
        Member member = new Member();
        member.no = rs.getInt("mno");
        member.name = rs.getString("name");
        member.email = rs.getString("email");
        list.add(member); 
      }
      return list;
    }// try() {}
  }

}

5단계 - 기존의 MemberDaoProxy를 MariaDBMemberDao로 교체한다.

  • com.bitcamp.board.handler.MemberHandler 클래스 변경

  • com.bitcamp.board.ClientApp 클래스 변경

    • MemberHandler 객체를 생성할 때 생성자에 파라미터를 넘기지 않는다.
  • MemberHandler class

public class MemberHandler extends AbstractHandler {

  MariaDBMemberDao memberDao;

  public MemberHandler() {
    super(new String[] {"목록", "상세보기", "등록", "삭제", "변경"});

    memberDao = new MariaDBMemberDao();
  }

  @Override
  public void service(int menuNo){
    try{
      switch (menuNo) {
        case 1: this.onList(); break;
        case 2: this.onDetail(); break;
        case 3: this.onInput(); break;
        case 4: this.onDelete(); break;
        case 5: this.onUpdate(); break;
      }
    }catch(Exception e) {
      throw new RuntimeException();
    }
  }

  private void onList() throws Exception{
    List<Member> members = memberDao.findAll();
    if(members == null) {
      System.out.println("목록을 가져오는데 실패했습니다!");
      return;
    }
    System.out.println("번호\t이름\t이메일");

    for (Member member : members) {
      System.out.printf("%d\t%s   %s\n",
          member.no , member.name, member.email);
    }

  }

  private void onDetail() throws Exception{
    int no = Prompt.inputInt("조회할 회원 번호? ");
    Member member = memberDao.findByNo(no);

    if(member == null) {
      System.out.println("해당 번호의 회원이 없습니다!");
      return;
    }

    System.out.printf("이름: %s\n", member.name);
    System.out.printf("이메일: %s\n", member.email);
    System.out.printf("등록일: %tY-%1$tm-%1$td %1$tH:%1$tM\n", member.createdDate);

  }

  private void onInput() throws Exception{
    Member member = new Member();

    member.name = Prompt.inputString("이름? ");
    member.email = Prompt.inputString("이메일? ");
    member.password = Prompt.inputString("암호? ");

    memberDao.insert(member);
    System.out.println("회원을 등록했습니다.");
  }

  private void onDelete() throws Exception{
    int no = Prompt.inputInt("삭제할 회원 번호? ");

    if(memberDao.delete(no)  == 1) {
      System.out.println("삭제하였습니다.");
    } else {
      System.out.println("해당 이메일의 회원이 없습니다!");
    }

  }

  private void onUpdate() throws Exception{
    int no = Prompt.inputInt("변경할 회원 번호? ");

    Member member = memberDao.findByNo(no);

    if(member == null) {
      System.out.println("해당 번호의 회원이 없습니다!");
      return;
    }

    member.name = Prompt.inputString("이름?(" + member.name + ") ");
    member.email = Prompt.inputString("이메일?(" + member.email + ") ");
    member.password = Prompt.inputString("암호? ");

    String input = Prompt.inputString("변경하시겠습니까?(y/n) ");
    if (input.equals("y")) {
      // 회원 변경하기
      if(memberDao.update(member)==1) {
        System.out.println("변경했습니다.");
      }else {
        System.out.println("변경 실패했습니다!");
      }

    } else { // no
      System.out.println("변경 취소했습니다.");
    }
  }
}

6단계 - MariaDB 서버와 연동하는 BoardDao를 정의한다.

  • com.bitcamp.board.domain.Board 클래스 변경
    • createDate 필드를 Java.sql.Date 타입으로 변경
    • writer 필드를 int 타입 memberNo로 변경
    • 기타 메서드 정리
  • com.bitcamp.board.dao.MariaDBBoardDao 클래스 정의

7단계 - 기존의 BoardDaoProxy를 MariaDBBoardDao로 교체한다.

  • com.bitcamp.board.handler.BoardHandler 클래스 변경
  • com.bitcamp.board.ClientApp 클래스 변경
    • MemberHandler 객체를 생성할 때 생성자에 파라미터를 넘기지 않는다.

DBMS 도입전


DBMS 도입후


의존객체 생성위치


(c:connection 객체, T: Thread)

현재 방식의 문제점

  • 메서드 호출 → DB연결
  • 메서드 호출 종료 → DB 연결 종료

⇒ Connection 객체 생성에 시간이 많이 소요 되고, Connection Garbage가 많이 생성된다.

profile
https://github.com/Dingadung

0개의 댓글