ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] DTO, DAO, VO란?
    Java 2022. 2. 19. 00:01

    자바를 공부하던 중 DTO, DAO라는 단어들이 많이 보여서 확실하게 개념을 잡고 가고자 정리하게 되었습니다.

     

    DAO란?

    Data Access Object의 약자로, 데이터베이스의 data에 접근하기 위한 객체입니다.

    데이터베이스에 접근하기 때문에 Service와 DB를 연결하는 고리의 역할을 합니다.

    jdbc와 같은 곳에서 db connection을 받아오거나, DB와 서로 통신하는 기능을 담당하는 객체를 뜻합니다.

     

    아래의 코드는 DAO 클래스의 예제입니다.

    jdbc쪽 안 써보셨다면 이해가 어려울 수 있지만 단순히 DB와 연결하여 통신(조회, 삭제, 수정)할 수 있는 객체입니다.

    코드를 보시면 List<MemberDto>를 반환하네요? MemberDto라는 객체의 리스트를 반환하는데

    DTO란 무엇인지는 아래에서 살펴보겠습니다.

    package test.dao;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    import test.dto.MemberDto;
    import test.util.DBConnect;
    
    /*
     *   회원정보를 입력, 수정, 삭제 하는 non static 메소드를 3 개 만들어 보세요.
     *   
     *   메소드의 인자로 전달되는 회원 번호를 이용해서 회원 한명의 정보를 리턴하는 메소드를 만들어 보세요.
     *   
     *   전체 회원의 목록을 리턴하는 메소드를 만들어 보세요.
     */
    public class MemberDao {
       
       //회원 목록을 리턴해주는 메소드 
       public List<MemberDto> getList(){
          //회원 목록을 담을 객체를 미리 생성한다.
          List<MemberDto> list=new ArrayList<>();
          //필요한 객체를 담을 지역 변수 미리 만들기
          Connection conn = null;
          PreparedStatement pstmt = null;
          ResultSet rs = null;
          try {
             //Connection 객체의 참조값 얻어오기 
             conn = new DBConnect().getConn();
             //실행할 sql 문의 뼈대 미리 준비하기
             String sql = "SELECT num, name, addr"
                   + " FROM member"
                   + " ORDER BY num DESC";
             //PreparedStatement 객체의 참조값 얻어오기
             pstmt = conn.prepareStatement(sql);
             //? 에 필요한값 바인딩하기 
    
             //select 문 수행하고 결과를 ResultSet 으로 받아오기 
             rs = pstmt.executeQuery();
             while (rs.next()) {
                //cursor 가 위치한 곳의 칼럼 데이터를 빼오기 
                //row 하나당 하나의 MemberDto 객체를 생성해서 회원정보를 담고 
                MemberDto dto=new MemberDto();
                dto.setNum(rs.getInt("num"));
                dto.setName(rs.getString("name"));
                dto.setAddr(rs.getString("addr"));
                //ArrayList 객체에 누적 시킨다.
                list.add(dto);
             }
          } catch (Exception e) {
             e.printStackTrace();
          } finally {
             try {
                if (rs != null)
                   rs.close();
                if (pstmt != null)
                   pstmt.close();
                if (conn != null)
                   conn.close();
             } catch (SQLException e) {
             }
          }
          return list;
       }
       
       public MemberDto getData(int num) {
          //MemberDto 객체의 참조값을 담을 변수 미리 만들기
          MemberDto dto=null;
          
          //필요한 객체를 담을 지역 변수 미리 만들기
          Connection conn = null;
          PreparedStatement pstmt = null;
          ResultSet rs = null;
          try {
             //Connection 객체의 참조값 얻어오기 
             conn = new DBConnect().getConn();
             //실행할 sql 문의 뼈대 미리 준비하기
             String sql = "SELECT name, addr"
                   + " FROM member"
                   + " WHERE num=?";
             //PreparedStatement 객체의 참조값 얻어오기
             pstmt = conn.prepareStatement(sql);
             //? 에 필요한값 바인딩하기 
             pstmt.setInt(1, num);
             //select 문 수행하고 결과를 ResultSet 으로 받아오기 
             rs = pstmt.executeQuery();
             //만일 select 된 row 가 있다면
             if (rs.next()) {
                //cursor 가 위치한 곳의 칼럼 데이터를 빼오기 
                //String name=rs.getString("name");
                //String addr=rs.getString("addr");
                //MemberDto 객체를 생성해서 회원 정보를 담는다.
                dto=new MemberDto();
                dto.setNum(num);
                dto.setName(rs.getString("name"));
                dto.setAddr(rs.getString("addr"));
             }
          } catch (Exception e) {
             e.printStackTrace();
          } finally {
             try {
                if (rs != null)
                   rs.close();
                if (pstmt != null)
                   pstmt.close();
                if (conn != null)
                   conn.close();
             } catch (SQLException e) {
             }
          }
          
          return dto;
       }
       
       //회원 정보를 삭제하는 메소드
       public boolean delete(int num) {
          //필요한 객체를 담을 지역 변수 미리 만들기
          Connection conn = null;
          PreparedStatement pstmt = null;
          int flag = 0;
          try {
             //Connection 객체의 참조값 얻어오기 
             conn = new DBConnect().getConn();
             //실행할 sql 문의 뼈대 미리 준비하기
             String sql = "DELETE FROM member"
                   + " WHERE num=?";
             //PreparedStatement 객체의 참조값 얻어오기
             pstmt = conn.prepareStatement(sql);
             //? 에 필요한값 바인딩하기 
             pstmt.setInt(1, num);
             //sql 문 실행하기 (INSERT, UPDATE, DELETE)
             flag = pstmt.executeUpdate();
          } catch (Exception e) {
             e.printStackTrace();
          } finally {
             try {
                if (pstmt != null)
                   pstmt.close();
                if (conn != null)
                   conn.close();
             } catch (SQLException e) {
             }
          }
          if (flag > 0) {
             //성공
             return true;
          } else {
             //실패
             return false;
          }
    
       }
       
       //회원정보를 수정하는 메소드
       public boolean update(MemberDto dto) {
          //필요한 객체를 담을 지역 변수 미리 만들기
          Connection conn = null;
          PreparedStatement pstmt = null;
          int flag = 0;
          try {
             //Connection 객체의 참조값 얻어오기 
             conn = new DBConnect().getConn();
             //실행할 sql 문의 뼈대 미리 준비하기
             String sql = "UPDATE member"
                   + " SET name=?, addr=?"
                   + " WHERE num=?";
             //PreparedStatement 객체의 참조값 얻어오기
             pstmt = conn.prepareStatement(sql);
             //? 에 필요한값 바인딩하기 
             pstmt.setString(1, dto.getName());
             pstmt.setString(2, dto.getAddr());
             pstmt.setInt(3, dto.getNum());
             //sql 문 실행하기 (INSERT, UPDATE, DELETE)
             flag = pstmt.executeUpdate();
          } catch (Exception e) {
             e.printStackTrace();
          } finally {
             try {
                if (pstmt != null)
                   pstmt.close();
                if (conn != null)
                   conn.close();
             } catch (SQLException e) {
             }
          }
          if (flag > 0) {
             //성공
             return true;
          } else {
             //실패
             return false;
          }
    
       }
       
       //회원 정보를 추가(입력) 하는 메소드 
       public boolean insert(MemberDto dto) {
          //필요한 객체를 담을 지역 변수 미리 만들기
          Connection conn = null;
          PreparedStatement pstmt = null;
          int flag = 0;
          try {
             //Connection 객체의 참조값 얻어오기 
             conn = new DBConnect().getConn();
             //실행할 sql 문의 뼈대 미리 준비하기
             String sql = "INSERT INTO member"
                   + " (num,name,addr)"
                   + " VALUES(member_seq.NEXTVAL, ?, ?)";
             //PreparedStatement 객체의 참조값 얻어오기
             pstmt = conn.prepareStatement(sql);
             //? 에 필요한값 바인딩하기 
             pstmt.setString(1, dto.getName());
             pstmt.setString(2, dto.getAddr());
             //sql 문 실행하기 (INSERT, UPDATE, DELETE)
             flag = pstmt.executeUpdate();
          } catch (Exception e) {
             e.printStackTrace();
          } finally {
             try {
                if (pstmt != null)
                   pstmt.close();
                if (conn != null)
                   conn.close();
             } catch (SQLException e) {
             }
          }
          if (flag > 0) {
             //성공
             return true;
          } else {
             //실패
             return false;
          }
    
       }
    }

     

    DTO란?

    Data Transfer Object의 약자로, 계층 간 데이터 교환 역할을 합니다.

    계층 간 데이터 교환이 이루어질 수 있도록 하는 객체이기 때문에 특별한 로직을 가지지 않는 순수한 데이터 객체입니다.

    일반적으로 데이터와 그 데이터에 접근하기 위한 getters/setters만 가지고 있다.

     

    DTO를 사용하는 이유?

    외부와 통신하는 프로그램에 있어서 호출에 대한 비용은 비싸기 때문에 우리는 요청의 횟수를 줄이기 위해 한 번의 요청에 많은 데이터를 전송해야 합니다.

    JAVA에서는 반환값으로 여러 개의 값을 받을 수 없기 때문에 요청에 대한 모든 데이터를 보관할 수 있는 객체인 DTO를 만들어 사용합니다.

     

    사용자로부터 책의 이름, 가격, 저자에 대한 정보를 받아서 사용한다면 DTO가 없다면 책의 이름, 가격, 저자를 따로따로 호출하여 받아 써야 합니다.

    따라서 DTO라는 객체를 사용해서 책의 이름, 가격, 저자를 한 번에 관리합니다.

     

     

    DTO의 예시

    class DTO_BOOK {
    	private String name;
    	private int price;
    	private String author;
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getPrice() {
    		return price;
    	}
    
    	public void setPrice(int price) {
    		this.price = price;
    	}
    
    	public String getAuthor() {
    		return author;
    	}
    
    	public void setAuthor(String author) {
    		this.author = author;
    	}
    
    }

    DTO와 VO의 차이

    VO(Value Object)도 DTO와 동일한 개념이지만 DTO는 데이터를 전달하는데 의미가 있지만 VO는 읽기만 가능한 read-only 속성을 가진 객체로서 데이터 그 자체에 의미를 두고 있습니다.

     

    VO는 값이 읽기만 가능하기 때문에 값이 불변하며, 값을 수정할 수 없습니다.

     

    현실세계에서는 지폐의 일련번호들을 예시로 들 수 있습니다.

    지폐의 일련번호들은 모두 다르지만 우리는 이것을 모두 5만원권이라고 부릅니다.

    이 개념이 바로 VO입니다.

     

    정리

    용도

    DTO : 계층간 데이터 전달

    VO : 값 표현, 데이터 그 자체

     

    동등성 결정

    DTO : 값이 같다고 같은 객체는 아님

    VO : 값이 같으면 같은 객체

     

    가변 객체

    DTO : setter를 포함하면 가변 객체 가능하지만 권장하지는 않음

    VO : 절대안됨. 불변 객체

     

    로직

    DTO : getter/setter 외 로직이 없음

    VO : getter/setter 외 로직을 가질 수 있음.

    VO의 예시

    public class Money{
    	private final int value;
    	
    	public Moeny(final int value){
    		this.value = value;
    	}
    
    	public int getHalfValue(){
    		return value / 2;	
    	}
    	...
    }

    setter 메서드가 없는 모습을 볼 수 있습니다.

    VO는 "5만원권"의 개념이기 때문에 Money 인스턴스끼리 동등한 지를 컴파일러에게 물으면 동등하다고 대답해야 하지만 "다르다!" 라드 대답할 것입니다.

    왜냐하면 컴파일러는 인스턴스간의 동등성을 비교할 때 해시 코드를 통해 진행하기 때문입니다.

    따라서 VO는 자바 컴파일러가 비교를 해시코드가 아닌 필드 값으로 하도록 유도하기 위해 equals, hashCode 메서드를 필수로 구현해야 합니다.

    Equals, hashCode 메서드 구현 코드

    public class Money {
        private final int value;
        
        public Money(final int value) {
            this.value = value;
        }
        
        public int getHalfValue() {
            return value / 2;
        }
        
        @Override
        public boolean equals(Object o) {
            if(this == o) {
                return true;
            }
            if (!(o instanceof Money)) {
                return false;
            }
            Money money = (Money) o;
            return value == money.value;
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(value);
        }
    }

     

     

     

    https://hyeon9mak.github.io/DTO-vs-VO/

     

    DTO vs VO

    3대450(이었던) 킹갓인비의 2월 25일 DTO vs VO 테코톡을 정리해보자!

    hyeon9mak.github.io

    https://kafcamus.tistory.com/13

     

    DTO란 무엇인가, VO와의 비교

    오늘은 다음의 고민 때문에 글을 작성하게 되었다. DTO가 정확히 뭘 의미하는 거지? DTO를 꼭 써야하는 이유가 뭐지? DTO랑 VO를 많이 비교하던데, 뭐가 다른거지? DTO란 무엇인가 DTO(Data Transfer Object,

    kafcamus.tistory.com

    https://live-for-myself.tistory.com/108

     

    [Java] JDBC #2 DAO

    DAO는 Data Access Object로 데이터베이스의 데이터에 접근하기 위한 객체이다. 저번 게시물에서 DTO(Data Transfer Object)를 활용해보았는데 이번 게시물에서는 CRUD 작업을 수행하는 DAO 클래스를 활용해볼

    live-for-myself.tistory.com

     

    댓글

Designed by Tistory.