[Spring] DAO, DTO, VO

김현수·2024년 7월 10일
0
post-custom-banner

DAO(Data Access Object):

  • 데이터베이스의 접근하는 객체

  • 프로젝트 서비스 모델에 해당하는 부분과 데이터베이스를 연결한다.

  • 직접 데이터베이스로 접근하여 데이터의 CRUD 작업을 수행함

  • DB에 접근하기 위한 로직 & 비즈니스 로직을 분리하기 위해 사용

    • 이는 효율적으로 커넥션을 관리할 수 있음
    • 또한 도메인 로직으로부터 DB와 관련된 메커니즘을 숨겨 보안 향상
  • DAO 코드 예시

public class TestDao {
public void add(TestDto dto) throws ClassNotFoundException, SQLException {
	
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/dao_Db";
    private static final String USER = "root";
    private static final String PASSWORD = "1234";   
		
		String sql = "SELECT * FROM vouchers";

        try {
            con = DriverManager.getConnection(URL, USER, PASSWORD);
            stmt = con.createStatement();
            res = stmt.executeQuery(sql);
            while (res.next()) {
                System.out.println(res.getString("id") + " ");
                System.out.println(res.getString("value") + " ");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

    preparedStatement.setString(1, dto.getName());
    preparedStatement.setInt(2, dto.getValue());
    preparedStatement.setString(3, dto.getData());
    preparedStatement.executeUpdate();
    preparedStatement.close();

    connection.close();

	}
}
  • Dto를 매개변수로 받아서 Driver, URL, username, password를 입력하여 데이터베이스의 접근하여 Create를 해주는 것을 확인할 수 있다.

  • 스프링 프로젝트를 할 때 많이 사용화는 JpaRepository<>를 상속받는 Repository 객체들도 DAO라고 볼 수 있다.

public interface UserRepository extends JpaRepository<Item, Long> {
....
}

Domain(Entity):

  • 실제 DB와 매핑되는 클래스

  • @Entity, @Column, @Id 등과 같은 annotation 사용

  • DB테이블 내에 존재하는 칼럼만 필드로 가져야 하고 상속받거나 구현체서는 안된다.

    • DTO는 데이터 전송만 함.

DTO(Data Transfer Object)

  • 로직을 가지지 않는 순수한 데이터 객체 (getter, setter만 가지는 클래스)

  • 여러 레이어간 데이터를 주고받을 때 사용하고 주로 View Controller 사이에서 활용

  • DB를 저장할 때는 Entity에 저장하고 계층간 데이터 이동에는 DTO 이용.

  • 왜 그렇게 사용할까?

    1. Entity의 비밀번호와 같은 민감한 정보를 포함한 모든 속성이 외부에 노출된다.
    2. Entity는 UI에서 사용하지 않는 데이터까지 보유하고 있는 등 요청과 응답 객체가 항상 엔티티와 같지는 않다..
    3. Controller에서 조작을 통해 실수로 엔티티의 메서드를 호출하거나 상태를 변경시킬 위험이 존재한다.
    4. Model과 View가 강하게 결합되어 View의 요구사항 변화가 Model에 영향을 끼치기 쉽다.(관심사 분리를 위해)
    5. Validation 코드와 Entity 속성 코드를 분리할 수 있다.
  • 데이터 전달만을 위한 객체이기 때문에 getter, setter만 필요하고 나머지 필요 없음

  • 구현 방식에 따라 가변 객체, 불변 객체 가능

  • 가변 객체 예시(getter + setter메소드 가능)

// 가변 객체 DTO
// 기본생성자로 생성 후 값을 유동적으로 변경 
public class DtoEx {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
  • 불변 객체 예시(getter만 가능)
// 불변 객체 DTO
// 생성시 지정했던 값이 변하지 않고 getter() 메소드만 사용 가능
public class DtoEx {
    private final String name;
    private final int age;

    public DtoEx(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

VO(Value object)

  • DTO와 유사하지만 DTO와 달리 setter 메소드를 가지지 않아 읽기만 가능(불변)
  • getter메소드를 포함하여 이외의 비즈니스 로직 포함 가능
  • 두 객체의 모든 필드 값이 동일하면 같은 객체이다 가 핵심 정의
    • 따라서 equals와 hashCode의 오버라이딩하여 위 정의를 실현시키는게 중요.
  • 예시
// VO예제
// 값을 표현만 하기 때문에 setter()메소드는 사용하지 않는다.
public class VoEx {
    static class Money{
        private final int value;

        Money(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
				
	// 사용자 생성 메소드이지만 setter형태의 메소드가 아니므로 무관함
        public String printMoney(){
            return this.value + "원";
        }
					
	// 두 객체의 모든 필드 값들이 모두 같으면 같은 객체이도록 만들기 위한 오버라이딩
		@Override
        public int hashCode() {
            return Objects.hash(value);
        }

        @Override
        public boolean equals(Object obj) {
            if(this == obj)
                return true;
            if(obj == null || getClass() != obj.getClass())
                return false;
            Money money = (Money) obj;
            if(value == money.value)
                return true;
            else
                return false;
        }
    }
}

Q: 그러면 domain이 DTO or VO이고 Repository가 DAO인거 아닌가요?

domain == vo, repository == dao

이렇게 똑같이 봐도 괜찮은 건가요?

같은 것이라면 왜 vo, dao가 아닌 다른 이름을 사용한 것인지,

다른 것이라면 (vo, dao)와 (domain, repository)의 차이점에 대해서도 알려주시면 감사하겠습니다.

A:

domain != vo 입니다.

vo는 2가지 의미로 사용됩니다.

1. 단순히 데이터 값을 전달하기 위한 용도로 사용되는 객체라는 뜻 (DTO와 같은 뜻으로 혼용해서 사용합니다. 저는 이 경우 DTO라고 합니다. DTO = 데이터를 전송하는 목적으로 사용하는 객체이지요.)

2. 도메인 주도 설계에서 이야기하는 값 객체(Value Object)의 의미가 있습니다. 이 부분에 대한 자세한 내용은 JPA 기본편 강의에서 자세히 설명드립니다.(저는 vo라고 하면 이 의미로 사용합니다.)
//이부분은 찾아보니 equals를 오버라이딩 해야한다는 vo를 의미하는듯.

repository := dao (비슷함)

이 둘은 거의 같다고 생각하셔도 무방합니다. 좀 더 깊이있게 차이를 설명하면, repotiroy는 엔티티 객체를 보관하고 관리하는 저장소이고, dao는 데이터에 접근하도록 DB접근 관련 로직을 모아둔 객체입니다. 둘다 개념의 차이일뿐 실제로 개발할 때는 비슷하게 사용됩니다.

domain과 repository 질문 - 인프런

참고자료:

https://velog.io/@jeong_hun_hui/DTO를-사용해야하는-이유는-무엇일까

https://velog.io/@leesomyoung/Java-DAO-DTO-VO의-개념

post-custom-banner

0개의 댓글