2022.09.08/

Jimin·2022년 9월 8일
0

비트캠프

목록 보기
39/60
post-thumbnail
  • board-app 프로젝트 수행
      1. Connection 객체 공유하기
      1. Connection 객체 공유하기 II - 의존 객체 주입 방식
      1. DAO 객체를 교체하기 쉽게 만들기 - 의존 객체 주입과 인터페이스
      1. 트랜잭션 다루기 - 자동 커밋과 수동 커밋

의존 객체 생성 및 Connection 생성


메서드 호출할 때마다 Connection 생성

Connection 객체 생성에 시간이 많이 소요

이유? → Auth(인증, 권한)

  1. 사용자 인증 수행(Authentication)
  2. 권한 검사(Authorization)

Connection 가비지가 많이 생성

⇒ 메모리 낭비

실제로 Connection 객체를 공유하는 경우로 테스트 했을 경우와 Connection 객체를 공유하지 않고 사용할 때마다 생성하는 경우로 테스트를 했을 때,
공유하는 경우의 속도가 빠른 것을 확인할 수 있었다.


Connection 객체 공유하기


Connection 객체 공유하는 방법

  • DAO마다 Connection 객체 보유 (good)
  • DAO의 메서드는 같은 Connection 객체 사용 (bad)

board-app project 적용

1단계 - DAO 클래스에서 한 개의 커넥션을 생성하여 공유한다.

  • com.bitcamp.board.dao.MariaDBMemberDao class 변경
    • Connection 객체를 MariaDBMemberDao 생성자에 만들고 각각의 메소드는 하나의 Connection 객체를 공유한다.
  • com.bitcamp.board.dao.MariaDBBoardDao class 변경
    • Connection 객체를 MariaDBBoardDao 생성자에 만들고 각각의 메소드는 하나의 Connection 객체를 공유한다.

MariaDBMemberDao class

public class MariaDBMemberDao {
  Connection con;
  public MariaDBMemberDao() throws Exception{
    con = DriverManager.getConnection(
    "jdbc:mariadb://localhost:3306/studydb", "study", "1111");
  }
 .
 .
 .

Connection 객체 공유하기2
- 의존 객체 주입 방식

의존 객체 주입(injection) 방식으로 Connection 객체를 공유하기

1. 의존 객체 직접 생성 → 사용

Dao가 10개 있다면 모든 DAO마다 Connection 객체가 생성된다.
⇒ 하나의 DBMS에 10개의 Connection 객체가 생성된 후 연결된다.
→ 좋지 않다.

2. 의존 객체를 주입 받기 → 사용

의존객체주입(Dependency injection; DI)

의존 객체: Dependency

  • 객체 공유가 쉽다.
  • 기존 코드를 손대지 않고 객체를 교체할 수 있다.

board-app project 적용

1단계 - ClientApp에서 Connection 객체를 준비한다.

  • com.bitcamp.board.clientApp 클래스 변경
    • main() 에서 connection 객체를 생성해서 Handler class로 connection 객체를 파라미터로 넘겨준다.
  • clientApp class
public static void main(String[] args) {
    try (
        // DAO가 사용할 커넥션 객체 준비
        Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb", "study", "1111");
        )
    {
      System.out.println("[게시글 관리 클라이언트]");

      welcome();

      // 핸들러를 담을 컬렉션을 준비한다.
      ArrayList<Handler> handlers = new ArrayList<>();
      handlers.add(new BoardHandler(con));
      handlers.add(new MemberHandler(con));

      .
      .
      .

2단계 - Connection 객체를 주입하는 방식으로 DAO를 변경한다.

생성자에 connection 객체를 받아오고 그 connection 객체를 공유한다.

  • com.bitcamp.board.dao.MariaDBMemberDao class 변경

  • com.bitcamp.board.dao.MariaDBBoardDao class 변경

  • MariaDBMemberDao class

public class MariaDBBoardDao {
  Connection con;
  // DAO가 사용할 의존 객체 Connection을 생성자의 파라미터로 받는다.
  // 의존객체: 이 객체가 작업하는데 사용하는 것.
  public MariaDBBoardDao(Connection con) throws Exception {
    this.con = con;
  }
  
  ....
  

3단계 - Connection 객체를 받을 수 있도록 변경한다.

생성자에 connection 객체를 받아오고 그 connection 객체를 공유한다.

  • com.bitcamp.board.Handler.MemberHandler class 변경
  • com.bitcamp.board.Handler.MemberHandler class 변경

4단계 - Handler를 생성할 때 Connection 객체를 주입한다.

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

DAO 객체를 교체하기 쉽게 만들기 - 의존객체 주입과 인터페이스

Handler에서 DAO 객체를 교체하기 쉽게 만들기

1단계 - Handler에서 DAO를 주입 받을 수 있도록 변경한다.

  • com.bitcamp.board.dao.MariaDBMemberDao class 변경

  • com.bitcamp.board.dao.MariaDBBoardDao class 변경

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

  • MariaDBMemberDao class

private MariaDBBoardDao boardDao;

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

    this.boardDao = boardDao;
  }
  
  ...

2단계 - DAO의 사용법을 통일하여 DAO 교체시 코드 변경을 최소화시킨다.

  • com.bitcamp.board.dao.MemberDao 인터페이스 정의

  • com.bitcamp.board.dao.MariaDBMemberDao 클래스 변경

    • MemberDao 인터페이스 규칙에 맞춰 클래스를 정의한다.
  • com.bitcamp.board.dao.BoardDao 인터페이스 정의

  • com.bitcamp.board.dao.MariaDBBoardDao 클래스 변경

    • BoardDao 인터페이스 규칙에 맞춰 클래스를 정의한다.
  • MemberDao interface
    dbms에 따라 dao를 수정해야하므로 dao의 메서드 호출에 대한 규칙을 인터페이스라는 문법으로 정의하자.

public interface MemberDao {

  int insert(Member member)throws Exception;

  int update(Member member) throws Exception;

  Member findByNo(int no)  throws Exception;

  int delete(int no) throws Exception;

  List<Member> findAll() throws Exception;

}
  • MariaDBMemberDao class
public class MariaDBMemberDao implements MemberDao{
	...

}

인터페이스: 객체 사용 규칙을 정의한 것

인터페이스를 정의하면, 클래스를 제작하는 개발자가 자기마음대로 코드를 변경할 수 없고 규칙에 따라 만들어야 한다.
⇒ 객체를 다른 걸로 교체하기가 쉽다. 유지보수가 쉽다. ← 기존 코드의 변경이 최소화되기 때문이다.

3단계 - Handler에서도 인터페이스 규칙을 적용한다.

DBMS에 상관없이 MemberDao 규칙을 따르는 DAO을 사용하겠다!
→ MariaDBMemberDao클래스가 MemberDao 인터페이스의 구현체이므로 데이터타입을 MemberDao로 선언할 수 있다.

  • clientApp class
public static void main(String[] args) {
    
    ...
    
      // DAO 객체를 준비한다.
      MariaDBMemberDao memberDao = new MariaDBMemberDao(con);
      MariaDBBoardDao boardDao = new MariaDBBoardDao(con);

      // 핸들러를 담을 컬렉션을 준비한다.
      ArrayList<Handler> handlers = new ArrayList<>();
      handlers.add(new BoardHandler(boardDao));
      handlers.add(new MemberHandler(memberDao));
  • MemberHandler class
public class MemberHandler extends AbstractHandler{
  // DBMS에 상관없이 MemberDao 규칙을 따르는 DAO을 사용하겠다!
  private MemberDao memberDao; 

  public MemberHandler(MemberDao memberDao) throws Exception{
    
    ....
    

트랜잭션 다루기 - 자동커밋과 수동커밋

여러 개의 데이터 변경 작업을 한 단위로 묶는 방법

  • 부모 테이블의 데이터를 삭제하는 방법
  • 여러 개의 데이터 변경 작업을 한 단위로 묶는 방법

1단계 - 회원 데이터를 삭제할 때 게시글 데이터도 묶어 함께 삭제한다.

  • com.bitcamp.board.dao.MariaDBMemberDao class 변경

    • delete() 메서드에 수동 커밋을 설정한다.
  • MariaDBMemberDao class

public int delete(int no) throws Exception{
    try(
        PreparedStatement pstmt1 = con.prepareStatement( "delete from app_board where mno = ?"); // 자식 데이터 지우기
        PreparedStatement pstmt2 = con.prepareStatement( "delete from app_member2 where mno = ?") // 부모 데이터 지우기
        ) //try ()
    {
      // 커넥션 객체를 수동 커밋 상태로 설정한다.
      con.setAutoCommit(false);
      // 자식 데이터 지우기 - 회원이 작성한 게시글 삭제
      pstmt1.setInt(1, no); 
      pstmt1.executeUpdate();
      // 부모 데이터 지우기 - 회원 데이터 삭제
      pstmt2.setInt(1, no); 
      int count =  pstmt2.executeUpdate();

      // 현재까지 작업한 데이터 변경 결과를 실제 테이블에 적용해 달라고 요청한다.
      con.commit();
      return count;
    } /*try() {}*/catch(Exception e) {
      // 예외가 발생하면 마지막 커밋 상태로 돌린다.
      // => 임시 데이터베이스에 보관된 이전 작업 결과를 모두 취소한다.
      con.rollback();

      // 예외 발생 사실을 호출자에게 전달한다.
      throw e;
    }finally {
      // 삭제 작업 후 자동 커밋 상태로 전환한다.
      con.setAutoCommit(true);
    }
  }

Application Server 구조로 전환

1. 이전 C/S 아키텍처(구조)

C/S Application Architecture

  • local에 App을 설치
    → App의 기능 변경 → 각 local에 App. 재설치
    ⇒ 유지보수가 어렵다.
  • 원격의 DBMS 공유
    → local에 설치된 실행파일을 통해 원격 DBMS의 접속 정보를 알아낼 수 있다.
    ⇒ 보안에 매우 취약하다.

2. Application Server Architecture

  • 로컬에서 DBMS에 직접 접근하는 것을 막는다.
    ⇒ 보안 문제 해결
  • 실제 작업은 서버에서 수행한다.
    ⇒ App기능 변경이 쉽다.
    → App에 기능을 추가하거나 변경, 삭제해도 local App은 서버가 응답한 결과를 단순히 출력하는 일만 한다.

프로젝트 수행 절차

1. 프로젝트 주제 선정

  • 프로젝트 비전 수집🌟
    • 현황 및 문제점
    • 해결 방안 및 이점
  • UI 프로토타입 작성🌟
    • 주요 요구사항에 대한 화면 정의
  • 1명 이상의 조
    팀당 2개 이상의 조

2. 요구사항 정의

  • 프로젝트 비전 개정🌟
  • Use-case 모델링🌟
    • Actor 식별
    • use-case 식별
  • UI 프로토타입 상세화 (UI 스토리보드)🌟

3. DB 설계

  • DB 모델링
    • 논리 모델
    • 물리 모델
  • 테이블 생성
  • 예제 데이터 준비

4. 프로젝트 구현

프로젝트 생성

구현

테스트

리뷰

5. 클라우드로 이전

클라우드 서버 준비

설정

실행

6. 발표

  • 내용 발표
  • 시연
profile
https://github.com/Dingadung

0개의 댓글