[JAVA] JPA란?

JunWoo An·2023년 11월 8일
0

스파르타코딩클럽

목록 보기
15/46

DB를 직접적으로 다룰때 어떤 문제들이 발생할까?

앞선 프로젝트를 통해 DB에 ID, name, content 등 여러 데이터를 한대 묶은 객체형태로 CRUD해왔다. 이때 SQL문을 통해 직접 DB에 접속하여 테이블을 생성하고 애플리케이션에서 SQL을 작성하여 JDBC를 통해 클라이언트로부터 받은 데이터를 DB에 저장, 조회하거나 삭제해왔으며 그 결과를 다시 객체형태로 변환하여 클라이언트에게 반환하였다. 또한 코드 구현이 끝난후 만약 클라이언트의 데이터의 새로운 타입의 데이터가 추가된다면? 다시 일일히 SQL문을 수정하고 반환하는 객체의 형태 또한 수정을 해야한다. 이는 개발자로서 로직 개발보다는 SQL 작성 및 SQL문 수정에 따른 수정요소에 더 많은 노력이 들어간다. 그렇다면 이러한 문제를 어떻게 해결할까?

ORM과 JPA

ORM : Object-Relational Mapping, ORM은 객체와 DB의 관계를 매핑 해주는 도구

ORM의 정의를 통해 알수있듯이 개발자가 일일히 객체와 DB간의 관계를 직접 매핑해왔지만 이제는 ORM을 사용하여 이를 자동적으로 처리하여 개발자가 로직 개발에 좀더 집중할수 있게되었다.

자바에서는 JPA라 불리는 Java PErsistence API(자바 ORM 기술에 대한 표준명세)를 제공하고있다.

JPA는 애플리케이션과 JDBC 사이에서 동작하고 있으며 JPA를 사용하면 DB 연결 과정을 직접 개발하지 않아도 자동적으로 처리해준다. 또한 객체를 통해 간접적으로 DB 데이터를 다룰수 있기때문에 매우 쉽게 DB작업을 처리 할수있다.

더 나아가서 JPA가 표준명세이고 이를 실제로 구현한 프레임워크 중 사실상 표준하이버네이트이다. SpringBoot에서는 기본적으로 하이버네이트 구현체를 사용중이다.

사실상 표준 : 기업간의 치열한 경쟁을 통해 시장에서 결정되는 비 공식적 표준

Entity

여기서 추가적으로 Entity(엔티티)의 개념이 추가되는데 엔티티는 JPA에서 관리되는 객체들을 뜻한다. Entity클래스는 DB테이블과 매핑되어 JPA에 의해 관리가 되며 클라이언트의 요청으로 받은 데이터(Dto)를 Entity로 변환 후 JPA를 통해 로직에 의해 요청이 DB에 수행이 되고 요청이 끝난 후 Entity타입을 Dto로 변환하여 클라이언트에게 반환한다.

JPA를 사용하기 위해서는 위와 같이 resources 폴더 아래에 META-INF폴더와 그 안에 persistence.xml파일을 생성해준 뒤 아래와 같이 설정을 해줘야한다. SpringBoot의 경우에는 application.properties에 하이버네이트 properties만 넣어주면 자동으로 해당파일을 바탕으로 만들어준다.

겉보기에는 복잡해보이지만 하나하나 차근차근 보면

   <persistence-unit name="memo">
 		<class>com.sparta.entity.Memo</class>
        <properties>
			<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="jakarta.persistence.jdbc.user" value="root"/>
            <property name="jakarta.persistence.jdbc.password" value="1234"/>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/memo"/>
            
            <property name="hibernate.hbm2ddl.auto" value="update" />
            
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.use_sql_comments" value="true"/>
        </properties>

unit name은 이름을 설정하며 다음으로 class는 해당 엔티티로 관리할 클래스의 경로를 지정하는 코드이며 그 아래로는 JDBC드라이버, DB의 userID와 password 그리고 DB의 해당 데이터베이스의 경로를 나타낸다.
또한 하이버네이트 관련 속성들중 'update'라 작성되있는 부분은 create , create-drop , update, validate 네가지로 작성할수있는데 각 기능은 아래와같다.

create : SessionFactory 시작시 스키마를 삭제하고 다시 생성
create-drop : SessionFactory 종료시 스키마를 삭제
update : SessionFactory 시작시 객체 구성와 스키마를 비교하여 컬럼 추가/삭제 작업을 진행함. 기존의 스키마를 삭제하지 않고 유지.
validate : SessionFactory 시작시 객체구성과 스키마가 다르다면 예외 발생시킴.

이제 엔티티 클래스의 코드구현을 살펴보면 아래와 같다.

package com.sparta.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity // JPA가 관리할 수 있는 Entity 클래스 지정
@Table(name = "memo") // 매핑할 테이블의 이름을 지정
public class Memo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // nullable: null 허용 여부
    // unique: 중복 허용 여부 (false 일때 중복 허용)
    @Column(name = "username", nullable = false, unique = true)
    private String username;

    // length: 컬럼 길이 지정
    @Column(name = "contents", nullable = false, length = 500)
    private String contents;
}

처음 보는 어노테이션들이 있는데 이들의 기능은 아래와 같다.

  • @Entity : JPA가 관리할 수 있는 Entity 클래스로 지정할 수 있습니다.
    • @Entity(name = "Memo") : Entity 클래스 이름을 지정할 수 있습니다. (default: 클래스명)
    • JPA가 Entity 클래스를 인스턴스화 할 때 기본 생성자를 사용하기 때문에 반드시 현재 Entity 클래스에서 기본 생성자가 생성되고 있는지 확인해야 합니다.
  • @Table : 매핑할 테이블을 지정해줍니다.
    • @Table(name = "memo") : 매핑할 테이블의 이름을 지정할 수 있습니다. (default: Entity 명)
  • @Column :
    • @Column(name = "username") : 필드와 매핑할 ****테이블의 컬럼을 지정할 수 있습니다. (default: 객체의 필드명)
    • @Column(nullable = false) : 데이터의 null 값 허용 여부를 지정할 수 있습니다. (default: true)
    • @Column(unique = true) : 데이터의 중복 값 허용 여부를 지정할 수 있습니다. (default: false)
    • @Column(length = 500) : 데이터 값(문자)의 길이에 제약조건을 걸 수 있습니다. (default: 255)
  • @Id : 테이블의 기본 키를 지정해줍니다.
    • 이 기본 키는 영속성 컨텍스트에서 Entity를 구분하고 관리할 때 사용되는 식별자 역할을 수행합니다.
      • 따라서 기본 키 즉, 식별자 값을 넣어주지 않고 저장하면 오류가 발생합니다.
    • @Id 옵션만 설정하면 기본 키 값을 개발자가 직접 확인하고 넣어줘야 하는 불편함이 발생합니다.
  • @GeneratedValue(strategy = GenerationType.IDENTITY) : 해당 옵션을 추가해주면 개발자가 직접 id 값을 넣어주지 않아도 자동으로 순서에 맞게 기본 키가 추가됩니다.(Auto_increment 기능)
profile
도전하는 사람

0개의 댓글