카테고리 없음

[JAVA/Spring Boot] Spring Data JPA 연동하기

때래뚫 2023. 7. 24. 16:57
JPA 연동하기

JDK : 1.8
Spring Boot : 2.3.1

JPA : Hibernate

DBMS : MySQL

 

오늘은 JPA연동하는 방법에 대해서 포스팅을 하려고합니다.

단순 연동 방법이 필요하신 분들은 서론을 건너뛰고 보시면 될 것같습니다.

JPA란?

JPA란 MyBatis랑 비슷하게 DB와 서버의 연결을 간편하게 해주는 인터페이스입니다. 하지만 Mybatis와 다르게 엔티티에 직접 테이블과 컬럼을 지정하고 쿼리문을 객체지향적으로 코딩할 수 있게 도와줍니다.

 

JPA의 구성

JPA의 역할을 이해하기 쉽도록 그림을 한장 퍼왔습니다. 위 설명과 조합하시면 이해가 빠르실 것 같습니다.

출처 : https://velog.io/@tmdgh0221/JPA-%EA%B8%B0%EB%B3%B8%ED%8E%B8-%EC%A0%95%EB%A6%AC

그림을 보시면 JPA라는 인터페이스로 JDBC를 감싸고 있습니다. 저희가 JPA의 함수와 문법을 이용해서 쿼리문을 날려달라고 요청하면, JPA는 JDBC에 맞게 해당 요청을 쿼리문으로 변환하여 DB와 연동합니다. 

 

왜 MyBatis에서 JPA로 넘어가나요?

개인적인 생각으로는 MyBatis는 Mapping파일을 경로로 잡는 config파일을 xml로 만들고 또한 Mapper파일을 새로 생성하여 쿼리문을 작성하기때문에 객체지향적인 설계와는 거리가 멀고, 엔티티를 쉽게 사용하려면 별칭으로 등록하고 또한 그마저도 사소한 오타가 존재할 시 오류가 발생합니다. JDBC를 직접 사용하는 것보다는 낫겠지만 그래도 개발시에 상당히 힘들고, 유지보수 역시 하나하나 뒤져보면서 Entity의 값과 name을 비교하는것이 많이 힘듭니다.

 

하지만 JPA는 엔티티에서 그대로 컬럼, 테이블을 지정하고, MVC의 Model부분에서 객체지향적으로 쿼리문을 날리면 작성자의 목적에 맞게 변환시켜 데이터를 CRUD할 수 있게 되어있기 때문에 간편하고, 세팅이나 오류나 발생할 부분이 적어서 확실히 개발 효율을 증가시킬 수 있을 것같습니다.

 

Hibernate(JPA 구현체)

오늘 포스팅에서는 Hibernate라는 JPA 인터페이스의 구현체를 사용할 것입니다. 위 설명대로 JPA는 인터페이스 이기때문에, 작성되어있는 메서드를 구현해야합니다. 이런 것들을 이미 구현해놓은 구현체를 사용함으로서 쉽게 사용할 수 있습니다. 물론 Hibernate말고도 EclipseLink, DataNucleus, OpenJPA, TopLink Essentials등 여러가지가 존재하니, 상황에 맞게 사용하시면 되겠습니다.

 

JPA 연동방법

우선 스프링 부트 프로젝트를 생성해야합니다. 모르시는 분들은 밑의 글을 참고해주세요, 여러 설정중에 JPA 연동과 관련된 라이브러리는 Spring-data-JPA와 사용할 DB의 connector입니다. 참고 Spring-data-JPA만 넣으시면 자동으로 hibernate에 대한 라이브러리도 추가됩니다.

2023.07.14 - [JAVA] - [Spring] Spring boot 프로젝트 생성 방법

 

[Spring] Spring boot 프로젝트 생성 방법

Spring boot란? - Spring Boot란 Spring Framework 프로젝트 생성시 처음하면 매우매우 복잡하고 절대로 쉽게 할 수 없는 초기 설정 및 라이브러리 세팅을 간단하게 만들어주는 프레임워크(FrameWork)입니다. -

lucky-web.tistory.com

Spring Data JPA와 Hibernate에 대한 라이브러리 추가
DB 커넥터 라이브러

 

그 이후 생성된 프로젝트의 외부 라이브러리를 확인하면, hibernate와 JPA에 대한 라이브러리를 확인할 수 있습니다.

hibernate관련 라이브러리
Spring Data JPA 관련 라이브러리

 

외부 라이브러리를 확인하셨다면 src/resources 디렉터리 밑에 application.properties파일을 생성하고 해당 내용을 작성합니다.

application.properties추가

 

application.properties 내용

하나씩 보시면 server.port는 연결할 서버의 포트, url은 jdbc와 커넥션할 DB 스키마의 주소(JDBC에 사용하는 url이나 Mybatis에서 설정해놓은 url과 같습니다.) 유저 아이디와 비밀번호, 그리고 연결할 때 사용하는 드라이버 주소까지 입력합니다.

 

그리고 그 밑은 어떤 DB를 사용하는지 지정하는 부분이고, Database-platform역시 같습니다.

 

3번째는 어떤 단계의 로그부터 남길지를 정하는 단계로, log4j의 여러단계에서 용도에 맞게 지정하시면됩니다.

 

이런 설정들은 더 많이 있지만 필요할 때 마다 알아보시면서 추가하시면 좋을 것같습니다.

 

 

 

 

이제는 엔티티(Entity)와 DB 테이블을 연동하겠습니다. 우선 가상의 테이블을 만들겠습니다.

가상의 테이블

member테이블은 pid,username,name 총 3가지의 컬럼을 가지고 있는 테이블입니다. 해당 테이블을 연결하는 엔티티는 당연히 컬럼의 갯수에 맞게 만들어야겠죠?

@Getter // lombok
@Builder // lombok
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity(name="member")// 테이블 명 작성
public class MemberEntity {

    @Id // pk
    @GeneratedValue(strategy = GenerationType.IDENTITY) // == 시퀀스
    private long pid;

    @Column(nullable = false,unique = true,length = 30) // 속성값 정하기
    private String username;

    @Column(nullable = false, length = 100)
    private String name;

    public MemberEntity(String username, String name) {
        this.username = username;
        this.name = name;
    }
}

테이블 member를 바라보는 MemberEntity클래스를 생성했습니다. @Entity(name = "member")어노테이션은 연결된 DB의 member라는 이름을 가진 테이블과 연동한다는 뜻입니다.

- @Id는 해당 컬럼이 pk라는 것을 의미합니다.

- @GeneratedValue(strategy = GenerationType.IDENTITY)는 MySQL의 auto_increment나 Oracle의 sequence와 같이 자동 숫자 증가를 나타내게 하는 어노테이션인데, GenerationType을 바꿈에 따라 여러가지로 조정할 수 있습니다.

- @Column은 테이블의 컬럼이라는 뜻을 나타내고, 컬럼의 여러가지 속성을 제어할 수 있습니다.

 

이제 JPA의 기능을 사용하기 위한 준비를 하겠습니다.

 

JPARepository생성

 

 

Interface생성

JPA를 끌어올 인터페이스를 생성하고, JPARepository를 상속받습니다.

package com.example.demo.repo;

import com.example.demo.entity.MemberEntity;
import org.springframework.data.jpa.repository.JpaRepository;


public interface MemberRepository extends JpaRepository<MemberEntity, Long> {

}

따로 입력하시지 않아도 됩니다. 그저 JPA의 기능을 끌어쓰기 위한 인터페이스이기때문입니다.

 

 

JPA 작동

 

이제 JPA를 사용하기만 하면됩니다. 보통은 Service에 구현하여 데이터를 가져오고 원하는 방식으로 수정하기도 하지만, 지금은 작동을 보여드리기위하여 Controller에 바로 JPARepository의 의존성을 주입하고 사용해보겠습니다.

 

Controller

package com.example.demo.controller;

import com.example.demo.entity.MemberEntity;
import com.example.demo.repo.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController// @ResponseBody + @Controller
@RequiredArgsConstructor // final 객체를 Constructor Injection해줌.( like @Autowired)
@RequestMapping("/v1")
public class MemberController {
    private final MemberRepository repository;
    /*
    * 멤버조회
    * @return
    * */

    @GetMapping("member")
    public List<MemberEntity> findAllMember(){
        return repository.findAll();
    }

    /**
     * 회원가입
     *
     * @return
     */
    @PostMapping("member")
    public MemberEntity signUp() {
        final MemberEntity member = MemberEntity.builder().username("test_user@gmail.com")
                                                          .name("test user")
                                                          .build();
        return repository.save(member);
    }
}

코드를 보시면 방금 생성한 MemberRepository의 의존성을 주입하고, JPA에서 findAll이라는 함수를 사용하여 해당 값을 responseBody에 return하도록 되어있습니다.

findAll함수를 사용하면 어떤 쿼리문이 작동될까요?

우선 인터페이스 코드를 다시보면...

package com.example.demo.repo;

import com.example.demo.entity.MemberEntity;
import org.springframework.data.jpa.repository.JpaRepository;


public interface MemberRepository extends JpaRepository<MemberEntity, Long> {

}

MemberEntity를 JpaRepository에 담음으로서 해당 인터페이스는 member테이블을 바라보게 되어있습니다.

findAll은 해당 테이블의 모든 데이터를 조회하기때문에

select

          *

from

          member;

쿼리문이 실행되는 것입니다.

그럼 현재 DB에있는 데이터와 웹에서 리턴받는 데이터가 같은지 확인해보겠습니다.

5개의 데이터가 존재한다.

총 5개의 데이터가 존재하는것을 볼 수 있습니다. 그럼 웹에서 findAll()함수를 사용하는 페이지로 가서 5개가 나오는지 확인해보겠습니다.

 

총 5개가 나오는 것을 볼 수 있습니다. 이렇게 JPA의 세팅과 사용방법에 대해 다뤄보았습니다.