[Java] DAO, DTO, Entity class 구분, Annotaion

eunhye_·2022년 12월 31일
0

Java

목록 보기
10/10

DAO(Data Access Object) 란?

repository package : 실제로 DB에 접근하는 Persistence Layer

Service와 DB를 연결하는 고리의 역할을 한다.

SQL 문을 사용하여 DB에 접근한 후 적절한 API를 제공한다.

public class UsersDAO {

	public static boolean addUsers(UsersDTO user) throws SQLException{
	실행 코드 ...
	}
}

DTO(Data Transfer Object) 란?

  • 계층간 데이터 교환을 위한 객체(Java Beans)이다.

→ DB에서 데이터를 얻어 Service나 Controller 등으터 보낼 때 사용하는 객체를 말한다.

DB의 데이터가 Presentation Logic Tier로 넘어오면 DTO의 모습으로 오고간다.

로직을 갖고 있지 않는 순수한 데이터 객체이다.

  • Request와 Response용 DTO는 View를 위한 클래스로 자주 변경이 필요하다.

** VO vs DTO

  • VO는 DTO와 동일한 개념이지만 read only 속성을 갖는다.
  • VO는 특정한 비즈니스 값을 담는 객체이고, DTO는 Layer간의 통신 용도로 오고가는 객체를 말한다.
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor

public class UsersDTO {
	private int id;
			....
}

Entity Class 란?

domain package - 실제 DB의 테이블과 매칭될 클래스, 최대한 외부에서 Entity 클래스의 getter method를 사용하지 않도록 해당 클래스 안에서 필요한 로직 method을 구현한다.

** Entity Class와 DTO를 분리하는 이유?

  • View Layer와 DB Layer의 역할을 철저하게 분리하기 위해서
  • 테이블과 매핑되는 Entity 클래스가 변경되면 여러 클래스에 영향을 끼치게 되는 반면 View와 통신하는 DTO 클래스(Request / Response 클래스)는 자주 변경되므로 분리하여 사용하는 것이 효율적이다.
  • Domain Model을 아무리 잘 설계했다고 해도 각 View 내에서 Domain Model의 getter만을 이용해서 원하는 정보를 표시하기가 어려운 경우가 종종 있다. 이런 경우 Domain Model 내에 Presentation을 위한 필드나 로직을 추가하게 되는데, 이러한 방식이 모델링의 순수성을 깨고 Domain Model 객체를 망가뜨리게 된다. 또한 Domain Model을 복잡하게 조합한 형태의 Presentation 요구사항들이 있기 때문에 Domain Model을 직접 사용하는 것은 어렵다.

즉 DTO는 Domain Model을 복사한 형태로, 다양한 Presentation Logic을 추가한 정도로 사용하며 Domain Model 객체는 Persistent만을 위해서 사용한다.

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor

@Entity
public class UsersEntity {
	@Id
	@Column(length = 20)
	private String id;
	.....
}

전체 구조 (Package 기준)

Controller(web)

해당 요청 url에 따라 적절한 view와 mapping 처리

적절한 ResponseEntity(DTO)를 body에 담아 Client에 반환

@WebServlet("/home")
public class HomeController extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		process(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		process(request, response);
	}
	
	protected void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		
		...
	}
}

Service

Business Logic을 처리한다.

DAO로 DB에 접근하고 DTO로 데이터를 전달받은 다음, 비지니스 로직을 처리해 적절한 데이터를 반환한다.

public class Service {
	public static void notExistUser(String id) throws NotExistException, SQLException{
		UsersDTO user = UsersDAO.getUser(id);
		if(user == null){
			throw new NotExistException("검색하신 User은 존재하지 않습니다.");
		}
	}
}

Entity class에서 Annotation 사용

@Entity

@Entity가 붙은 클래스는 JPA가 관리하는 것으로, 엔티티라고 불린다.

**final 클래스, enum, interface, inner class 에는 사용할 수 없음

  • 속성 Name : JPA에서 사용할 엔티티 이름을 지정.  보통 기본값인 클래스 이름을 사용

@Table

엔티티와 매핑할 테이블을 지정, 생략 시 매핑한 엔티티 이름을 테이블 이름으로 사용

  • 속성 Name : 매핑할 테이블 이름 (default. 엔티티 이름 사용)
    Catalog : catalog 기능이 있는 DB에서 catalog 를 매핑 (default. DB 명) Schema : schema 기능이 있는 DB에서 schema를 매핑 uniqueConstraints : DDL 생성 시 유니크 제약조건을 만듦      →스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용

데이터베이스 스키마 자동 생성 기능

JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원

클래스의 매핑 정보와 데이터베이스 방언을 사용하여 데이터베이스 스키마 생성

애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성

사용

//스키마 자동 생성 기능 사용을 위해 persistence.xml에 속성 추가

<property name="hibernate.hbm2ddl.auto" value="create" />c
  • 속성

    create: 기존 테이블을 삭제하고 새로 생성(DROP + CREATE)

    create-drop : CREATE 속성에 추가로 애플리케이션을 종료할 때 생성한 DDL을 제거(DROP + CREATE + DROP)

    update : DB 테이블과 엔티티 매핑 정보를 비교해서 변경 사항만 수정

    validate: DB 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않음.DDL을 수행하지 않음

    none: 자동 생성 기능을 사용하지 않음

  • 주의

    개발 초기 단계는 create 또는 update

    초기화 상태로 자동화된 테스트를 진행하는 개발자 환경과 CI서버는 create 또는 create-drop

    테스트 서버는 update 또는 validate

    스테이징과 운영 서버는 validate 또는 none

테이블 명이나 컬럼 명이 생략되면 자바의 카멜 표기법을 테이블의 언더스코어 표기법으로 매핑하는 방법

// Before
@Column(name="role_type")
private RoleType roleType;

//After
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />

@Column

객체 필드를 테이블 컬럼에 매핑

@Column(nullable = false)
private String name; 

@Column(unique = true)
private String joinDate; 

@Column(columnDefinition = "varchar(100) default 'EMPTY'")
private String data; 

@Column(length = 400)
private Strin infor; 

@Column(precision = 10, scale = 2)
private BigDecimal data;

속성

  • name: 필드와 매핑할 테이블 컬럼 이름 (default. 객체의 필드 이름)
  • nullable(DDL) : null 값의 허용 여부 설정, false 설정 시 not null (default. true) @Column 사용 시 nullable = false 로 설정하는 것이 안전
  • unique(DDL) : @Table 의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 적용
  • columnDefinition(DDL) : 데이터베이스 컬럼 정보를 직접 줄 수 있음, default 값 설정   (default. 필드의 자바 타입과 방언 정보를 사용해 적절한 컬럼 타입을 생성)
  • length(DDL) : 문자 길이 제약조건, String 타입에만 사용 (default. 255)
  • percision, scale (DDL) : BigDecimal, BigInteger 타입에서 사용. 아주 큰 숫자나 정밀한 소수를 다룰 때만 사용(default. precision = 19, scale = 2)

@Enumerated

자바의 enum 타입을 매핑할 때 사용

  • 속성 value : EnumType.ORDINAL : enum 순서를 데이터베이스에 저장 
       EnumType.STRING : enum 이름을 데이터베이스에 저장 
    (default. EnumType.ORDINAL)

@Temporal

날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용

@Temporal(TemporalType.DATE) // 날짜
private Date date;  

@Temporal(TemporalType.TIME) // 시간
private Date time;  

@Temporal(TemporalType.TIMESTAMP) // 날짜와 시간
private Date dateAndTime; 
  • 속성

    TemporalType.DATE : 날짜, 데이터베이스 data 타입과 매핑 (2020-12-18)

    TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑 (23:36:33) 

    TemporalType.TIMESTAMP : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑 (2020-12-18 23:36:33)  → (default. TemporalType은 필수로 지정)

@Temporal 을 생략하면 자바의 Date와 가장 유사한 timestamp로 정의

@Transient

이 필드는 매핑하지 않음데이터베이스에 저장하지 않고 조회하지도 않음객체에 임시로 어떤 값을 보관하고 싶을 때 사용

@Access

  • 필드 접근 : AccessType.FIELD 로 지정  필드에 직접 접근 (private도 접근 가능)
  • 프로퍼티 접근: AccessType.PROPERTY 로 지정 접근자 Getter를 사용

Reference

https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html

https://data-make.tistory.com/610

0개의 댓글