Spring JPA - 개요와 환경세팅

김재현·2022년 8월 8일
0

Programmers

목록 보기
13/28
  • 스프링 웹 어플리케이션의 데이터 저장 계층에 대해 이해.
    • JDBC 템플릿 이용.
    • Mybatis이용.
    • ORM 프레임워크인 JPA이용.
  • JPA에 대해 이해.
  • 스프링데이터 JPA에 대해 이해.
  • 스프링데이터 JPA를 이용한 REST API 서버 구축.

1일차.

  • JPA 소개
    • ApplicationLayer에서 Database Layer에 접근하는 방법에 대해 학습.
      • JDBC Template, 쿼리매퍼(Mybatis) 소개
      • ORM(JPA)
    • JPA란 무엇인가?
    • JPA는 왜 필요한가?
  • JPA 프로젝트 실행하기 (IntelliJ + Maven)
    • 실습을 위한 환경을 세팅.

JPA 소개

  • Java Persistence API

  • Java 어플리케이션에서는 JDBC API라는 것을 통하여 데이터 저장 계층에 접근하게 되어 있다. JDBC API인터페이스는 JDBC 드라이버라는 각각의 구현체를 통해 동일한 인터페이스로 구현되어 있다.
	예제 코드
	@Test
    void jdbc_sample() {
        try {
            Class.forName(JDBC_DRIVER);

            Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);
            log.info("Connection 획득");
            Statement statement = connection.createStatement();
            log.info("Statement 획득");

            log.info("쿼리 실행");
            statement.executeUpdate(DROP_TABLE_SQL);
            statement.executeUpdate(CREATE_TABLE_SQL);

            statement.executeUpdate(INSERT_SQL);
            ResultSet resultSet = statement.executeQuery("SELECT id, first_name, last_name FROM customers WHERE id = 1");

            while(resultSet.next()) {
                log.info(resultSet.getString("first_name"));
            }

            log.info("반납, 반납");
            statement.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  • 어떤 드라이버를 사용할 것인지 명시 > Connection 획득 > Connection을 통해 statement 객체 생성 > statement 객체를 통해 RDB와 통신 > ResultSet 객체를 통해 결과값 조회 > 사용한 statement, Connection 반환.

JDBC Template

  • JDBC Template를 이용해서 데이터 계층에 접근이 가능하다.
    기존 JDBC를 이용했을 때의 반복적인 작업을 JDBC Template이 대신 수행해준다.
  • .update 메서드를 이용해서 데이터 조회 및 수정이 가능하다.
    JDBC Template가 제공하는 여러 메서드를 이용해 손쉽게 결과를 조작할 수 있다.

  • JDBC Template는 코드상의 SQL구문을 작성하고 있다. 소스코드가 길어지면, 코드와 쿼리가 섞이면서 추후 유지보수할 때 관리가 어려워지게 된다.
  • QueryMapper가 등장하게 되고, 그 중 대표적인 것이 Mybatis.

Mybatis

  • JDBC의 반복적인 작업을 쿼리매퍼인 Mybatis가 대신 수행해 준다.
  • 자바 코드와 쿼리를 분리해 줌.
  • 쿼리 수정으로 자바 코드 수정이나 컴파일하는 작업을 하지 않아도 됨.

사용 방법

  • @ 에노테이션을 사용하는 방법.
    @Insert, @Update, @Select 등의 에노테이션을 이용해서 에노테이션의 파라미터로 쿼리를 넣어주는 방법.
// Using Annotation
@Mapper
public interface CustomerMapper {
    @Insert("INSERT INTO customers (id, first_name, last_name) VALUES(#{id}, #{firstName}, #{lastName})")
    void save(Customer customer);

    @Update("UPDATE customers SET first_name=#{firstName}, last_name=#{lastName} WHERE id=#{id}")
    void update(Customer customer);

    @Select("SELECT * FROM customers")
    List<Customer> findAll();

    @Select("SELECT * FROM customers WHERE id = #{id}")
    Customer findById(@Param("id") long id);
}
  • .xml을 사용하는 방법.
    xml 파일에 쿼리문을 명시해주고 어떤 인터페이스와 매핑되는지 mapper를 설정해줌.
// Using XML
@Mapper
public interface CustomerXmlMapper {
    void save(Customer customer);
    void update(Customer customer);
    Customer findById(long id);
    List<Customer> findAll();
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kdt.lecture.repository.CustomerXmlMapper">
    <insert id="save">
        INSERT INTO customers (id, first_name, last_name)
        VALUES (#{id}, #{firstName}, #{lastName})
    </insert>

    <update id="update">
        UPDATE customers
        SET first_name=#{firstName},
            last_name=#{lastName}
        WHERE id = #{id}
    </update>

    <select id="findById" resultType="customers">
        SELECT *
        FROM customers
        WHERE id = #{id}
    </select>

    <select id="findAll" resultType="customers">
        SELECT *
        FROM customers
    </select>
</mapper>

  • type-aliases-package
    • JDBC 템플릿, JDBC API는 쿼리 결과가 resultSet에 담겨져 나옴. 그러나 resultSet을 조작하는 것은 번거로움.
    • Mybatis는 type-aliases-package에 정해놓은 java객체에다 resultSet의 결과를 자동으로 맵핑. 쿼리 결과를 어떤 객체에 맵핑할지, 어떤 패키지에 명시할지에 대한 설정이 type-aliases-package.
  • configuration : 기본적인 설정
    • map-underscore-to-camel-case : 테이블에 필드명을 언더바 형태로 표시.
      type-aliases-package에 명시한 객체에는 'camel case 형태로 맵핑을 시켜주겠다'고 명시한 것.
  • default-fetch-size : 'select all query'를 했을 때 한번에 가져올 수 있는 최대 개수.
  • default-statement-timeout
    • JDBC API에서 statement 객체라는 것을 이용해서 RDB에 쿼리를 날림. statement는 RDB와 통신하는 객체.
    • RDB와 통신할 때 default timeout을 얼마로 할 것인지 설정하는 것.
  • mapper-locatinos
    • Mybatis는 xml을 통해서 쿼리 관리 가능.
    • 쿼리를 어디에서 관리할 것인지에 대한 설정.
  • 코드와 쿼리를 따로 관리하며, 유지보수할 때 이점을 갖을 수 있도록 하는 것이 Mybatis와 같은 쿼리 맵퍼 프레임워크.
    Mybatis를 사용하면 JDBC Template의 문제점인 java 코드 상에 직접적으로 쿼리를 날리는 부분을 인터페이스를 이용하여 자바 코드에 직접 쿼리를 날리는 것이 아닌, 쿼리를 분리하고 메서드 호출을 통해서 쿼리를 내보낼 수 있음.
  • 쿼리 맵퍼나 JDBC Template의 한계가 RDB 등 relationDB와 자바 객체가 갖는 기본적인 패러다임이라는 연결고리가 생기게 됨.
  • JPA라는 것을 통해서 극복 가능.

JPA (Object Relation Mapper - ORM)

  • @Entity를 통해 객체가 실제 RDB 테이블과 맵핑이 되는 Entity객체라는 것을 명시해주게 됨.
    테이블이 어떤 테이블과 맵핑이 되는지를 @Table()을 통해서 명시를 해줄 수 있음. @Table()가 없으면 클래스 이름을 따라가게 되어있음.
  • @Id를 통해서 PK(Primary Key)가 어떤 것인지 명시해줄 수 있음.
  • Java의 객체와 RDB의 DB테이블을 맵핑을 시켜주어서, 객체가 변경되면 테이블도 변경, RDB의 테이블을 Java의 객체처럼 다룰 수 있게 해준다.
  • 테이블이 Entity라는 클래스로 관리가 되기 때문에 테이블의 모양과 객체의 모양을 정확히 맵핑시키고, 동일성을 유지하면서 관리를 할 수 있게 됨.
  • Object - 객체. Relation(DB) - 관계형 데이터베이스 테이블. 객체와 데이터베이스를 맵핑시켜주는 프레임워크.

JPA를 사용해야하는 이유

  • 생산성 증진
    • SQL에 의존적인 개발에서 탈피하여, 객체중심으로 생산적인 개발이 가능하게 됨.
  • 객체와 관계형 테이블의 패러다임 불일치
    • 객체지향 프로그래밍은 추상화, 캡슐화, 상속, 다형성 등을 지원한다.
    • 관계형 데이터베이스 데이터 중심으로 구조화되어 있으며, OOP의 특성을 지원하지 않는다.
  • Entity라는 객체가 RDB의 테이블과 맵핑이 되면서 추상화, 캡슐화, 상속, 다형성 등의 객체지향 프로그래밍의 특징을 사용할 수 있게 됨.

JPA의 기본 Annotation 정리

@, Annotation

@Entity

  • 데이터베이스의 테이블과 1:1로 매칭되는 객체 단위.
    Entity객체의 인스턴스 하나가 테이블에서 하나의 레코드 값을 의미한다.
    객체의 인스턴스를 구분하기 위한 유일한 키값을 갖는데 이것은 테이블 상의 Primary Key와 같은 의미를 갖으며 @Id어노테이션으로 표기된다.
  • 명시적으로 @Table의 name속성을 이용해 데이터베이스 상의 실제 테이블 명칭을 지정하지 않는다면, Entity클래스의 이름 그대로 CamelCase를 유지한 채 테이블이 생성되기 때문에, 테이블 이름을 명시적으로 작성하는 것이 관례.
    데이터베이스상에서 보편적으로 사용되는 명명법은 UnderScore가 원칙이기 때문이다.

@Column

  • @Column 어노테이션은 데이터베이스의 테이블에 있는 컬럼과 동일하게 1:1로 매칭되기 때문에 Entity 클래스 안에 내부변수로 정의된다.
  • 별다른 옵션을 설정하지 않는다면 생략도 가능. 즉, Entity클래스에 정의된 모든 내부변수는 기본적으로 @Column 어노테이션을 포함한다고 볼 수 있음.
  • @Entity와 동일하게 name속성을 명시하지 않으면 Entity 클래스에 정의한 컬럼 변수 이름으로 생성이 됨. CamelCase로 작성된 컬럼 변수가 있다면 UnderScore형식으로 name을 명시적으로 작성해야한다.
  • 컬럼은 실제 데이터가 가질 수 있는 최대 길이를 갖게 되는데, 이것은 데이터를 효율적으로 관리하기 위해서임. length 속성으로 길이를 명시할 수 있고, 지정하지 않는다면 기본인 255가 지정된다. precision, scale로 최대 길이 지정 가능.

@Id

  • 데이터베이스의 테이블은 기본적으로 유일한 값을 가지고 그것을 PK(Primary Key)라고 한다. 데이터베이스는 이 유일한 키 값을 기준으로 질의한 데이터를 추출해 결과셋으로 반환해 준다. 대부분의 경우 반드시 PK가 존재.
  • Entity 클래스 상에 PK를 명시해야되는데, @Id어노테이션을 이용해 PK임을 지정한다.

JPA 환경세팅

  • Spring Initializr로 생성한다.

  • Lombok 툴을 체크해주자.

  • Web은 Spring Web으로.

  • SQL은 Spring Data JPA와 H2 Database를 사용할 예정이니 체크한다.

  • yml설정을 해준다.

DataSource

  • 어떤 DataSource를 사용할 지 설정하는 부분.

JpaVenderAdapter

  • JPA는 하나의 인터페이스. 여러 구현체들이 구현을 해서 ORM 프레임워크를 만드는 것. 대표적인 구현체로는 HiberNate가 있음.
  • 어떤 구현체를 사용할지 결정하기 위하여 JpaVenderAdapter가 사용됨.

EntityManagerFactoryBean

  • Entity를 관리해주는 것이 EntityManager.
  • EntityManager를 만들어내는 Bean이 EntityManagerFactoryBean이다.

TransactionManager

  • Transaction을 관리해주는 빈.
  • @Transaction이 사용되면 엔티티매니저에 의해 엔티티들의 라이프사이클을 관리한다.

0개의 댓글