[Spring] JPA 사용해보기

minjonyyy·2025년 2월 6일

[Spring]

목록 보기
2/6
post-thumbnail

이전 과제에서는 JDBC template를 사용하여 SQL에 접근하고 사용하였다.

하지만 객체 지향 언어인 JAVA관계형 데이터베이스 사이에서는 여러 문제와 불편함이 발생한다.

이것을 해결해줄 JPA에 대하여 알아보고, 직접 시작해보자!


💫 JPA란 무엇일까?

JPA (Java Persistence API)

: 객체 지향 프로그래밍 언어인 java와 관계형 데이터베이스 간의 패러다임 불일치 문제를 해결하여 데이터베이스 작업을 객체 지향적으로 수행할 수 있도록 지원하는 기술이다.

  • JPA는 Java의 ORM 기술 표준(인터페이스)이며, 애플리케이션과 JDBC 사이에서 동작한다.
  • ORM (Object-Relational Mapping) : 객체와 관계형 데이터베이스 사이의 매핑
  • 기존 개발자가 데이터베이스와 상호작용하기 위하여 JDBC API를 사용했던 행위를 JPA가 대신해주는 것!

🤔 JPA를 사용하는 이유?

1. 생산성

: SQL문을 작성하거나 JDBC를 사용하는 것보다 훨씬 간편하게 객체 전달을 할 수 있다.
JPA를 사용하면 자바 컬렉션에 저장하듯이(ex. list.add()) 객체가 저장되어 조회가 간편하다.

jpa.presist(member); //저장
Member member = jpa.find(memberId); //조회
member.setName("수정할 이름"); //수정
jpa.remove(member); //삭제

JPA의 여러 기능들을 사용하여 데이터베이스 설계 중심의 패러다임을 객체 설계 중심으로 역전시킬 수 있다.

2. 유지보수성

: SQL을 직접 다루면 엔티티에 필드 하나만 추가해도 관련 SQL문과 JDBC 코드를 모두 수정해야 했다.
하지만 JPA를 사용하면 객체 필드가 수정되어도 JPA가 알아서 처리해준다!

3. 패러다임 불일치 문제 해결

: JPA는 상속 / 연관관계 / 객체 그래프 탐색 등 패러다임의 불일치 문제를 해결해준다.

🔗 패러다임 불일치 문제에 대하여 자세하게 알고싶다면?

4. 성능

JPA는 애플리케이션과 데이터베이스 사이에서 동작하기 때문에 효율적인 통신이 가능하다.
아래와 같은 상황에서, 멤버를 조회하는 SELECT SQL을 한 번만 데이터베이스에 전달하고 두 번째에는 조회한 멤버 객체를 재사용한다.

String memberId = "helloId";
Member member1 = jpa.find(memberId); //데이터베이스와 통신
Member member2 = jpa.find(memberId); //조회했던 멤버 객체 재사용

또한, JPA의 쓰기 지연(한번에 모아서 요청 보내기), 지연 로딩(필요할 때만 조회), 즉시로딩(한 번만 조회)등을 통해 네트워크 통신 비용 방면에서 좋은 성능을 지닌다.

5. 데이터 접근 추상화와 벤더 독립성

관계형 데이터베이스는 같은 기능도 벤더마다 사용법이 다른 경우가 많다.
하지만 JPA는 애플리케이션과 데이터베이스 사이에 추상화된 데이터 접근 계층을 제공하여, 특정 데이터베이스 기술에 종속되지 않도록 한다.


🪄JPA를 사용한 프로젝트를 시작해보자!

1. 프로젝트 생성

Spring Boot 선택
-> Build system : Gradle - Groovy
-> JDK : 버전17 선택

Dependencies

  • Spring Web
  • Lombok
  • Spring data JPA
  • MySQL Driver

만 추가해주었다! 지금 선택하지 않아도 추후에 추가 가능하다.

2. 데이터베이스 연결

Data Source
-> MySQL
-> User, Password 정보 추가한 후 Test Connection
-> 성공 후, board 스키마 생성

3. JPA 관련 설정하기

application.properties 에 아래의 코드들을 추가해준다.

// DataSource 설정
spring.datasource.url=jdbc:mysql://localhost:3306/board
spring.datasource.username=계정 //개인이 설정한 계정과 비밀번호로 수정하기
spring.datasource.password=비밀번호
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
// Hibernate 설정
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

✔️ Hibernate : JPA의 대표적인 구현체 중 하나이다.

  • 일단 auto=create 로 설정해두었기 때문에,
    프로젝트를 빌드할 때마다 테이블이 drop 후 새로 생성될 것이다.

  • DDL 자동 생성 속성

    설명
    create기존 테이블을 삭제(DROP) 후 다시 생성(CREATE)한다.
    create-dropDROP 후 CREATE 하고 종료시점에 테이블을 삭제(DROP)한다. 테스트 시 사용
    update변경된 사항만 DDL에 반영한다.
    validateEntity와 테이블이 정상적으로 매핑 되었는지 확인한다. 실패 시 예외 발생
    none속성을 사용하지 않는다.
  • hibernate.dialect : Hibernate가 사용하는 데이터베이스 방언(dialect)을 지정하는 설정.
    -> 데이터베이스와 Hibernate가 상호작용할 때 특정 데이터베이스에 맞게 SQL 구문을 자동으로 조정하는 역할을 수행한다.

프로젝트 준비 끝!👏

이제 Entity 를 만들어보자.


💠 BaseEntity.java

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime modifiedAt;

}

앞으로 다른 entity를 생성할 때 BaseEntity를 상속하면 생성/수정 시간은 자동으로 만들어진다.

  • @MappedSuperClass
    : 해당 어노테이션이 선언된 클래스를 상속받는 Entity에 공통 매핑 정보를 제공한다.
  • @EntityListeners(AuditingEntityListener.class)
    : Entity를 DB에 적용하기 전, 커스텀 콜백을 요청할 수 있는 어노테이션
  • @CreatedDate, @LastModifiedDate
    : 생성/수정 시점의 날짜를 자동으로 기록
  • createdAt 컬럼은 updatable = false로 생성 시간이 수정되지 못하도록 설정한다.

💠 Member.java

@Entity
@Table(name="member")
public class Member extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable=false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    private Integer age;
}
  • @GeneratedValue(strategy = GenerationType.IDENTITY)
    : 데이터베이스가 PK 자동 생성
    : Entity의 PK 필드에 사용하면 쓰기 지연을 무시하고 SQL Query를 실행한다.

<실행 결과>

  • 기존 데이터베이스에 생성되어있던 기록들은 모두 drop 후 새로 생성되는 member테이블
  • 앞서 @GeneratedValue(strategy = GenerationType.IDENTITY) 덕분에 id는 auto_increment로 설정되 것

실제 데이터베이스 탭에 들어가서 확인해보면 member 테이블이 자동으로 생성된 것을 볼 수 있다!!!

💠 Board.java

@Entity
@Table(name="board")
public class Board extends BaseEntity{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(columnDefinition = "longtext") //아주 긴 내용도 저장할 수 있음
    private String contents;
}

board 테이블까지 만들어주고 빌드해보면,

두 개의 테이블이 요로코롬 잘 생성되었다!!! 👏


🪄 연관관계 설정해보기

  • 한 명의 회원은 여러 개의 게시글을 작성할 수 있다. (N:1 단방향)
  • N 쪽의 엔티티에 @ManyToOne, @JoinColumn 작성
// Board.java 에 추가

@ManyToOne
@JoinColumn(name="member_id")
private Member member;
  • Board의 FK와 Member의 PK를 @JoinColumn 으로 매핑한다.
    .
    .

<실행결과>


새로 프로젝트 빌드 후 확인해보면, 연관관계가 잘 설정되었다!


이제 앞으로 JPA를 활용하여 데이터베이스에 쉽게 접근하여 사용하고, 프로젝트를 확장시킬 수 있게 되었다~!

다음 게시물에는 JPA로 데이터베이스를 설정한 후의 CRUD과정을 기록해보겠다.

0개의 댓글